api/v2/image.js
var _ = require('lodash');
var TopicProxy = require('../../proxy').Topic;
var TopicLike = require('../../proxy').TopicLike;
var TopicBoard = require('../../proxy').TopicBoard;
var BoardProxy = require('../../proxy').Board;
var BoardCollect = require('../../proxy').BoardCollect;
var UserProxy = require('../../proxy').User;
var counter = require('../../common/counter');
var config = require('../../config');
var EventProxy = require('eventproxy');
var at = require('../../common/at');
var renderHelper = require('../../common/render_helper');
var tools = require('../../common/tools');
var structureHelper = require('../../common/structure_helper');
var validator = require('validator');
/**
* @api {get} /v2/images 图片主题列表
* @apiDescription
* 获取本站图片主题列表
* @apiName getImages
* @apiGroup images
*
* @apiParam {Number} [page] 页数
* @apiParam {Number} [limit] 每一页的主题数量
* @apiParam {String} [q] 查询条件
*
* @apiPermission none
* @apiSampleRequest /v2/images
*
* @apiVersion 2.0.0
*
* @apiSuccessExample Success-Response:
* HTTP/1.1 200 OK
* {
"success": true,
"data": [
{
"id": "",
"author": "",
"tab": "ask",
"content": "",
"title": "",
"last_reply_at": "",
"good": false,
"top": false,
"reply_count": 2,
"visit_count": 8,
"create_at": "",
"author": {
"loginname": "admin",
"avatar_url": "//gravatar.com/avatar/80579ac37c768d5dffa97b46bb4754f2?size=48"
},
"reply": {
"author": {
"loginname": "admin",
"avatar_url": "//gravatar.com/avatar/80579ac37c768d5dffa97b46bb4754f2?size=48"
},
"content": "回复内容",
"create_at_ago", "几秒前",
"id": ""
}
}
]
}
*/
exports.index = function (req, res, next) {
var type = 'image';
var page = parseInt(req.query.page, 10) || 1;
page = page > 0 ? page : 1;
var limit = Number(req.query.limit) || config.list_topic_count;
var query = {};
query.deleted = false;
query.type = type;
if (!!req.query.q) {
query.title = new RegExp(req.query.q);
}
var options = {skip: (page - 1) * limit, limit: limit, sort: '-top -last_reply_at'};
var ep = new EventProxy();
ep.fail(next);
ep.all('topics', 'liked_topics', function (topics, liked_topics) {
let liked_t_ids = _.map(liked_topics, 'topic');
let structedTopics = [];
_.forEach(topics, function (topic) {
let structedTopic = structureHelper.image(topic);
liked_t_ids.forEach(function(lti){
let tid = lti.toString();
if (topic.id === tid) {
structedTopic.liked = true;
}
});
structedTopics.push(structedTopic);
});
res.send({success: true, data: structedTopics});
});
// 获得可以查看的Board列表
let queryBoard = {
$or: [{type: 'public'}]
};
if (!!req.session.user) {
queryBoard.$or.push({
user_id: req.session.user._id
});
}
BoardProxy.getBoardsByQuery(queryBoard, {}, ep.done('boards'));
ep.on('boards', function(boards) {
let boardIds = [];
_.forEach(boards, function (board) {
boardIds.push(board.id);
});
query.board = {$in: boardIds};
TopicProxy.getImagesByQuery(query, options, function (err, topics) {
if (!!req.session.user) {
// DONE (hhdem) 此处需要优化, 不要每次都获得全部喜欢的图片列表, 改为根据返回的图片列表, 查询是否like
let topic_t_ids = _.map(topics, 'id');
TopicLike.getTopicLikesByUserIdAndTopicIds(req.session.user._id, topic_t_ids, {}, ep.done('liked_topics'));
} else {
ep.emit('liked_topics', []);
}
ep.emit('topics', topics);
});
});
};
/**
*
* @api {get} /v2/images/sim 相似图片列表
* @apiDescription
* 获取本站相似图片列表, 根据hamming距离算法计算.
* @apiName simImages
* @apiGroup images
*
* @apiParam {String} id 查询相似的图片id
* @apiParam {String} sid 页数
* @apiParam {Number} limit 要查询的图片数量
*
* @apiPermission none
* @apiSampleRequest /v2/images/sim
*
* @apiVersion 2.0.0
*
* @apiSuccessExample Success-Response:
* HTTP/1.1 200 OK
*/
exports.sim = function (req, res, next) {
var limit = parseInt(req.query.limit, 10) || 3;
if (!req.query.id) {
return res.status(500).send({success: false, error_msg: "必要参数id未传."});
}
// 需从哪个id开始继续向下找
if (!req.query.sid) {
return res.status(500).send({success: false, error_msg: "必要参数sid未传."});
}
var topicId = req.query.id;
var sId = req.query.sid;
var ep = new EventProxy();
ep.fail(next);
TopicProxy.getTopicById(topicId, function (err, topic) {
if (err) {
return next(err);
}
if (!topic) {
res.status(404);
return res.send({success: false, error_msg: '图片不存在'});
}
var options = {limit: limit, sort: '-_id'};
// DONE (hhdem) 考虑如何把 hamming 距离改成 SIFT 算法或 pHash 算法, 最终改了 gHash, 依然需要优化
TopicProxy.getTopicsByQuery({type:'image', _id:{$lt:sId}, $where: "hammingDistance(this.image_hash, '" + topic.image_hash + "') < 25"}, options, function (err, topics) {
if (err) {
return next(err);
}
topics = topics.map(function (topic) {
return structureHelper.image(topic);
});
res.send({success: true, data: topics});
});
});
};
/**
* @api {post} /v2/images/like 喜欢图片
* @apiDescription
* 喜欢某图片
* @apiName likeImage
* @apiGroup images
*
* @apiUse ApiHeaderType
* @apiParam {String} id 要喜欢的图片id
*
* @apiPermission none
* @apiSampleRequest /v2/images/like
*
* @apiVersion 2.0.0
*
* @apiSuccessExample Success-Response:
* HTTP/1.1 200 OK
*/
exports.like = function (req, res, next) {
if (!req.body.id) {
return res.status(500).send({success: false, error_msg: "必要参数id未传."});
}
var ep = new EventProxy();
ep.fail(next);
var topicId = req.body.id;
var currentUser = req.session.user;
TopicProxy.getTopicById(topicId, function (err, topic) {
if (err) {
return next(err);
}
if (!topic) {
res.status(404);
return res.send({success: false, error_msg: '图片不存在'});
}
TopicLike.getTopicLike(currentUser.id, topic._id, function (err, doc) {
if (err) {
return next(err);
}
if (doc) {
return ep.emit('unlike_topic', topic);
}
return ep.emit('like_topic', topic);
});
});
ep.on('like_topic', function(topic) {
TopicLike.newAndSave(currentUser.id, topic._id, function (err) {
if (err) {
return next(err);
}
res.json({success: true});
});
UserProxy.getUserById(currentUser.id, function (err, user) {
if (err) {
return next(err);
}
user.like_image_count += 1;
req.session.user.like_image_count += 1;
user.save();
});
counter.topic(topic, 'like', function (err, image) {
if (err) {
return next(err);
}
});
});
ep.on('unlike_topic', function(topic) {
TopicLike.remove(currentUser.id, topic._id, function (err, removeResult) {
if (err) {
return next(err);
}
if (removeResult.result.n === 0) {
return res.json({success: false});
}
UserProxy.getUserById(currentUser.id, function (err, user) {
if (err) {
return next(err);
}
user.like_image_count -= 1;
req.session.user.like_image_count -= 1;
user.save();
});
counter.topic(topic, 'unlike', function (err, image) {
if (err) {
return next(err);
}
res.json({success: true});
});
});
});
};
/**
*
* DONE (hhdem) 修改为每次GET操作都生成新的topic对象, 但是图片地址不改变, 目前是添加了一个 TopicBoard 的关系对象
* 把图片Get到自己的board中
* @api {post} /v2/images/get Get图片
* @apiDescription
* Get某图片
* @apiName getImage
* @apiGroup images
*
* @apiUse ApiHeaderType
* @apiParam {String} topic_id 要 Get 的图片 id
* @apiParam {String} board_id 放入 Board 的 id
* @apiParam {String} [desc] 描述
* @apiParam {String[]} [tags] 标签
*
* @apiPermission none
* @apiSampleRequest /v2/images/get
*
* @apiVersion 2.0.0
*
* @apiSuccessExample Success-Response:
* HTTP/1.1 200 OK
*/
exports.getImage = function (req, res, next) {
req.checkBody({
'topic_id': {
notEmpty: {
options: [true],
errorMessage: 'topic_id 不能为空'
}
},
'board_id': {
notEmpty: {
options: [true],
errorMessage: 'board_id 不能为空'
}
}
});
var ep = new EventProxy();
var topic_id = req.body.topic_id;
var board_id = req.body.board_id;
var desc = req.body.desc;
var currentUser = req.session.user;
if (req.validationErrors()) {
return res.status(400).json({success: false, err_message: '参数验证失败', err: req.validationErrors()}).end();
}
// 获得要Get的topic对象
TopicProxy.getTopicById(topic_id, function (err, topic) {
// DONE(hhdem) 增加 err 的错误校验, 返回对应的错误信息
if (err) {
return next(err);
}
topic.geted_count += 1;
topic.save();
ep.emit('topic_from', topic);
});
// 获得Get目标Board对象
BoardProxy.getBoardById(board_id, function (err, board) {
if (err) {
return next(err);
}
board.topic_count += 1;
board.save();
ep.emit('board_to', board);
});
// 生成新的topic对象
ep.on('topic_from', function(fromTopic) {
var client_info = tools.client_info(req);
var topicImage = _.pick(fromTopic, structureHelper.image_copy_fields);
topicImage.client_info = client_info;
topicImage.title = desc;
topicImage.author = currentUser;
topicImage.get_from_topic = fromTopic._id;
topicImage.board = board_id;
TopicProxy.newAndSaveImage(topicImage, function (err, image) {
if (err) {
return next(err);
}
topicImage.id = image.id;
ep.emit('new_topic_saved', topicImage);
});
});
// 生成topicBoard关联对象
ep.all('new_topic_saved', 'board_to', function(newImage, board) {
TopicBoard.newAndSave(currentUser.id, newImage.id, board_id, desc || null, null, function (err, topicBoard) {
if (err) {
return next(err);
}
newImage.board = board;
ep.emit('new_topic_board_saved', newImage);
//res.json({success: true});
});
});
// 更新统计数据
UserProxy.getUserById(currentUser.id, function (err, user) {
// DONE (hhdem) 增加 err 的错误校验, 返回对应的错误信息
if (err) {
return next(err);
}
user.get_image_count += 1;
user.save();
req.session.user.get_image_count += 1;
ep.emit('user_count');
});
counter.topic(topic_id, 'getted', function (err, image) {
if (err) {
return next(err);
}
ep.emit('topic_count', image);
});
// TopicProxy.getTopicById(topic_id, function (err, topic) {
// // DONE (hhdem) 增加 err 的错误校验, 返回对应的错误信息
// if (err) {
// return next(err);
// }
// topic.geted_count += 1;
// topic.save();
// ep.emit('topic_count', topic);
// });
// 返回处理结果
ep.all('new_topic_board_saved', 'user_count', 'topic_count', function(newImage){
newImage.author = currentUser;
res.send({
success: true,
data: newImage
});
});
};
/**
* DONE (hhdem) 增加Board信息的返回,以及统计信息
* @api {get} /v2/images/:id 显示图片信息
* @apiDescription
* 获取某图片信息
* @apiName showImage
* @apiGroup images
*
* @apiParam {String} id 要获取的图片 id
*
* @apiPermission none
* @apiSampleRequest /v2/images/:id
*
* @apiVersion 2.0.0
*
* @apiSuccessExample Success-Response:
* HTTP/1.1 200 OK
*/
exports.show = function (req, res, next) {
var topicId = String(req.params.id);
var mdrender = req.query.mdrender === 'false' ? false : true;
var ep = new EventProxy();
if (!validator.isMongoId(topicId)) {
res.status(400);
return res.send({success: false, error_msg: '不是有效的话题id'});
}
ep.all('full_topic', 'boardImages', 'liked_topics', 'like_users', function (full_topic, boardImages, liked_topics, like_users) {
full_topic.board.images = boardImages;
full_topic = structureHelper.image(full_topic);
full_topic.liked = false;
let liked_users = _.map(like_users, 'user');
full_topic.like_users = liked_users;
if (!!liked_topics && _.isArray(liked_topics)) {
full_topic.liked = liked_topics.length > 0;
}
if (!!full_topic.image && full_topic.image.lastIndexOf('.') < 0) {
full_topic.image_fixed = full_topic.image + config.qn_access.style[2];
}
if (!!req.session.user) {
BoardCollect.getBoardCollect(req.session.user._id, full_topic.board.id, function (err, bc) {
if (bc) {
full_topic.board.is_collect = true;
} else {
full_topic.board.is_collect = false;
}
res.send({success: true, data: full_topic});
});
} else {
res.send({success: true, data: full_topic});
}
});
TopicProxy.getFullImage(topicId, ep.done(function (msg, topic, replies) {
if (!topic) {
res.status(404);
return res.send({success: false, error_msg: '话题不存在'});
}
if (!!msg) {
res.status(404);
return res.send({success: false, error_msg: msg});
}
TopicProxy.getTopicsByBoardId(topic.board._id, ep.done('boardImages'));
topic.replies = replies.map(function (reply) {
if (mdrender) {
reply.content = renderHelper.markdown(at.linkUsers(reply.content));
}
reply = structureHelper.reply(reply);
reply.reply_id = reply.reply_id || null;
if (reply.ups && req.user && reply.ups.indexOf(req.user.id) != -1) {
reply.is_uped = true;
} else {
reply.is_uped = false;
}
return reply;
});
ep.emit('full_topic', topic);
}));
if (!req.session.user) {
ep.emit('liked_topics', []);
} else {
TopicLike.getTopicLikesByUserIdAndTopicIds(req.session.user._id, [topicId], {}, ep.done('liked_topics'));
}
TopicLike.getLikeUsers(topicId, ep.done('like_users'));
ep.fail(function(err){
console.error(err);
});
};
/**
*
* DONE (hhdem) 删除图片
* @api {delete} /v2/images/:id 删除
* @apiDescription
* Get某图片
* @apiName deleteImage
* @apiGroup images
*
* @apiUse ApiHeaderType
* @apiParam {String} id 要删除的图片 id
*
* @apiPermission none
* @apiSampleRequest /v2/images/:id
*
* @apiVersion 2.0.0
*
* @apiSuccessExample Success-Response:
* HTTP/1.1 200 OK
*/
exports.delete = function(req, res, next) {
var topicId = String(req.params.id);
TopicProxy.remove(topicId, function (err, result) {
if (err) {
return next(err);
}
res.send({success: true});
});
};