您的位置:首页 > Web前端 > Node.js

Node.js 博客实例(十五)转载和转载统计功能

2014-08-29 13:28 573 查看
原教程 https://github.com/nswbmw/N-blog/wiki/_pages的第十五章,由于版本等的原因,在原教程基础上稍加改动即可实现。
          我们的设计思路是:当在线用户满足特定条件时,文章页面才会显示 转载 链接字样,当用户点击 转载 后,复制一份存储当前文章的文档,修改后以新文档的形式存入数据库,而不是单纯的添加一条指向被转载的文档的 "引用" ,这种设计是合理的,因为这样我们也可以将转载来的文章进行修改。

         首先,我们来完成转载文章的功能。

打开 post.js ,将 Post.prototype.save 内的:

var post = {
name: this.name,
head: this.head,
time: time,
title:this.title,
tags: this.tags,
post: this.post,
comments: [],
pv: 0
};
修改为:
var post = {
name: this.name,
head: this.head,
time: time,
title:this.title,
tags: this.tags,
post: this.post,
comments: [],
reprint_info: {},
pv: 0
};
打开 post.js ,在最后添加如下代码:

//转载一篇文章
Post.reprint = function(reprint_from, reprint_to, callback) {
mongodb.open(function (err, db) {
if (err) {
return callback(err);
}
db.collection('posts', function (err, collection) {
if (err) {
mongodb.close();
return callback(err);
}
//找到被转载的文章的原文档
collection.findOne({
"name": reprint_from.name,
"time.day": reprint_from.day,
"title": reprint_from.title
}, function (err, doc) {
if (err) {
mongodb.close();
return callback(err);
}
var date = new Date();
var time = {
date: date,
year : date.getFullYear(),
month : date.getFullYear() + "-" + (date.getMonth() + 1),
day : date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate(),
minute : date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate() + " " +
date.getHours() + ":" + (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes())
}

delete doc._id;//注意要删掉原来的 _id
doc.name = reprint_to.name;
doc.head = reprint_to.head;
doc.time = time;
doc.title = (doc.title.search(/[reprint]/) > -1) ? doc.title : "[reprint]" + doc.title;
doc.comments = [];
doc.reprint_info = {"reprint_from": reprint_from};
doc.pv = 0;

//更新被转载的原文档的 reprint_info 内的 reprint_to
collection.update({
"name": reprint_from.name,
"time.day": reprint_from.day,
"title": reprint_from.title
}, {
$push: {
"reprint_info.reprint_to": {
"name": doc.name,
"day": time.day,
"title": doc.title
}}
}, function (err) {
if (err) {
mongodb.close();
return callback(err);
}
});
//将转载生成的副本修改后存入数据库,并返回存储后的文档
collection.insert(doc, {
safe: true
}, function (err, post) {
mongodb.close();
if (err) {
return callback(err);
}
callback(err, post[0]);
});
});
});
});
};

这里我们在 Post.reprint() 内实现了被转载的原文章的更新和转载后文章的存储。

注意这一句:doc.title = (doc.title.search(/[reprint]/) > -1) ? doc.title : "[reprint]" + doc.title;

原教程里是doc.title = (doc.title.search(/[转载]/) > -1) ? doc.title : "[转载]" + doc.title;

汉字的话就会报错:

Express
500 TypeError: E:\nodejs\blog\views\article.ejs:3
1| <%- include header %>
2| <p>
>> 3|   <% if (user && (user.name == post.name)) { %>
4|   <span><a class="edit" href="/edit/<%= post.name %>/<%= post.time.day %>/<%= post.title %>">编辑</a></span>
5|   <span><a class="edit" href="/remove/<%= post.name %>/<%= post.time.day %>/<%= post.title %>">删除</a></span>
6| <% } %>

Cannot read property 'name' of null
1| <%- include header %>
2| <p>
>> 3|   <% if (user && (user.name == post.name)) { %>
4|   <span><a class="edit" href="/edit/<%= post.name %>/<%= post.time.day %>/<%= post.title %>">编辑</a></span>
5|   <span><a class="edit" href="/remove/<%= post.name %>/<%= post.time.day %>/<%= post.title %>">删除</a></span>
6| <% } %>
Cannot read property 'name' of null
at eval (eval at <anonymous> (E:\nodejs\blog\node_modules\ejs\lib\ejs.js:242:14), <anonymous>:31:89)
at eval (eval at <anonymous> (E:\nodejs\blog\node_modules\ejs\lib\ejs.js:242:14), <anonymous>:35:35)
at E:\nodejs\blog\node_modules\ejs\lib\ejs.js:255:15
at Object.exports.render (E:\nodejs\blog\node_modules\ejs\lib\ejs.js:293:13)
at View.exports.renderFile [as engine] (E:\nodejs\blog\node_modules\ejs\lib\ejs.js:323:20)
at View.render (E:\nodejs\blog\node_modules\express\lib\view.js:76:8)
at Function.app.render (E:\nodejs\blog\node_modules\express\lib\application.js:523:10)
at ServerResponse.res.render (E:\nodejs\blog\node_modules\express\lib\response.js:828:7)
at E:\nodejs\blog\routes\index.js:282:8
at E:\nodejs\blog\models\post.js:146:5
问题是处在转载之后返回的URL,本来是http://localhost:3000/u/123/2014-8-4/title   的形式,到但是如果这里title包含汉字就会报错。数据库里的数据是正常的。

打开 index.js ,在 app.get('/remove/:name/:day/:title') 后添加如下代码:
app.get('/reprint/:name/:day/:title', checkLogin);
app.get('/reprint/:name/:day/:title', function (req, res) {
Post.edit(req.params.name, req.params.day, req.params.title, function (err, post) {
if (err) {
req.flash('error', err);
return res.redirect(back);
}
var currentUser = req.session.user,
reprint_from = {name: post.name, day: post.time.day, title: post.title},
reprint_to = {name: currentUser.name, head: currentUser.head};
Post.reprint(reprint_from, reprint_to, function (err, post) {
if (err) {
req.flash('error', err);
return res.redirect('back');
}
req.flash('success', '转载成功!');
var url = '/u/' + post.name + '/' + post.time.day + '/' + post.title;
//跳转到转载后的文章页面
res.redirect(url);
});
});
});
         至此,我们给 转载 链接注册了路由响应。

         注意:我们需要通过 Post.edit() 返回一篇文章 markdown 格式的文本,而不是通过 Post.getOne 返回一篇转义后的 HTML 文本,因为我们还要将修改后的文档存入数据库,而数据库中应该存储 markdown 格式的文本。

         最后,我们在文章页(article.ejs)添加转载链接。

打开 article.ejs ,在:

<% if (user && (user.name == post.name)) { %>

  <span><a class="edit" href="/edit/<%= post.name %>/<%= post.time.day %>/<%= post.title %>">编辑</a></span>

  <span><a class="edit" href="/remove/<%= post.name %>/<%= post.time.day %>/<%= post.title %>">删除</a></span>

<% } %>

后添加如下代码:
<% var flag = 1 %>
<% if (user && (user.name != post.name)) { %>
<% if ((post.reprint_info.reprint_from != undefined) && (user.name == post.reprint_info.reprint_from.name)) { %>
<% flag = 0 %>
<% } %>
<% if ((post.reprint_info.reprint_to != undefined)) { %>
<% post.reprint_info.reprint_to.forEach(function (reprint_to, index) { %>
<% if (user.name == reprint_to.name) { %>
<% flag = 0 %>
<% } %>
<% }) %>
<% } %>
<% } else { %>
<% flag = 0 %>
<% } %>
<% if (flag) { %>
<span><a class="edit" href="/reprint/<%= post.name %>/<%= post.time.day %>/<%= post.title %>">转载</a></span>
<% } %>
        以上代码的意思是:我们设置一个 flag 标志,如果用户是游客,或者是该文章的目前作者,或者是该文章的上一级作者,或者已经转载过该文章,都会将 flag 设置为 0 ,即不显示 转载 链接,即不能转载该文章。最后判断 flag 为 1 时才会显示 转载 链接,即才可以转载这篇文章。

        最后,我们需要添加一个 原文链接 来指向被转载的文章。

打开 index.ejs 、user.ejs 、article.ejs,在第一个 <p class="info"> 里最后添加如下代码:
<% if (post.reprint_info.reprint_from) { %>
<br><a href="/u/<%= post.reprint_info.reprint_from.name %>/<%= post.reprint_info.reprint_from.day %>/<%= post.reprint_info.reprint_from.title %>">原文链接</a>
<% } %>
现在我们就给博客添加了转载功能。

       接下来我们添加转载统计。

打开 index.ejs 、user.ejs 、article.ejs ,将:

<p class="info">阅读:<%= post.pv %> | 评论:<%= post.comments.length %></p>

修改为:

<p class="info">
阅读:<%= post.pv %> |
评论:<%= post.comments.length %> |
转载:
<% if (post.reprint_info.reprint_to) { %>
<%= post.reprint_info.reprint_to.length %>
<% } else { %>
<%= 0 %>
<% } %>
</p>


现在我们就给博客添加了转载统计的功能。但工作还没有完成,假如我们要删除一篇转载来的文章时,还要将被转载的原文章所在文档的 reprint_to 删除遗留的转载信息。

打开 post.js ,将 Post.remove 修改为:
Post.remove = function(name, day, title, callback) {
//打开数据库
mongodb.open(function (err, db) {
if (err) {
return callback(err);
}
//读取 posts 集合
db.collection('posts', function (err, collection) {
if (err) {
mongodb.close();
return callback(err);
}
//查询要删除的文档
collection.findOne({
"name": name,
"time.day": day,
"title": title
}, function (err, doc) {
if (err) {
mongodb.close();
return callback(err);
}
//如果有 reprint_from,即该文章是转载来的,先保存下来 reprint_from
var reprint_from = "";
if (doc.reprint_info.reprint_from) {
reprint_from = doc.reprint_info.reprint_from;
}
if (reprint_from != "") {
//更新原文章所在文档的 reprint_to
collection.update({
"name": reprint_from.name,
"time.day": reprint_from.day,
"title": reprint_from.title
}, {
$pull: {
"reprint_info.reprint_to": {
"name": name,
"day": day,
"title": title
}}
}, function (err) {
if (err) {
mongodb.close();
return callback(err);
}
});
}

//删除转载来的文章所在的文档
collection.remove({
"name": name,
"time.day": day,
"title": title
}, {
w: 1
}, function (err) {
mongodb.close();
if (err) {
return callback(err);
}
callback(null);
});
});
});
});
};
看看效果,用户‘123’将转载用户‘dss’的一片文章:



再登录用户‘123’,转载这篇文章:



转载:



          顺着教程做到这里,其实还是存在一些问题的,将在最后一篇总结里贴出这些问题
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Node.js