pinclub/pinclub

View on GitHub
controllers/topic.js

Summary

Maintainability
F
1 wk
Test Coverage
/*!
 * nodeclub - controllers/topic.js
 */

/**
 * Module dependencies.
 */

var validator = require('validator');
var _ = require('lodash');

var at = require('../common/at');
var User = require('../proxy').User;
var Topic = require('../proxy').Topic;
var Forum = require('../proxy').Forum;
var TopicCollect = require('../proxy').TopicCollect;
var EventProxy = require('eventproxy');
var store = require('../common/store');
var config = require('../config');
var cache = require('../common/cache');
var logger = require('../common/logger');
var tools = require('../common/tools');

/**
 * Topic page
 *
 * @param  {HttpRequest} req
 * @param  {HttpResponse} res
 * @param  {Function} next
 */
exports.index = function (req, res, next) {
    function isUped(user, reply) {
        if (!reply.ups) {
            return false;
        }
        return reply.ups.indexOf(user._id) !== -1;
    }

    var topic_id = req.params.tid;
    var currentUser = req.session.user;

    if (topic_id.length !== 24) {
        return res.render404('此话题不存在或已被删除。');
    }
    var events = ['topic', 'other_topics', 'no_reply_topics', 'is_collect'];
    var ep = EventProxy.create(events,
        function (topic, other_topics, no_reply_topics, is_collect) {
            res.render('topic/index', {
                topic: topic,
                author_other_topics: other_topics,
                no_reply_topics: no_reply_topics,
                is_uped: isUped,
                is_collect: is_collect,
            });
        });

    ep.fail(next);

    Topic.getFullTopic(topic_id, ep.done(function (message, topic, author, replies) {
        if (message) {
            logger.error('getFullTopic error topic_id: ' + topic_id);
            return res.renderError(message);
        }

        topic.visit_count += 1;
        topic.save();

        topic.author = author;
        topic.replies = replies;

        // 点赞数排名第三的回答,它的点赞数就是阈值
        topic.reply_up_threshold = (function () {
            var allUpCount = replies.map(function (reply) {
                return reply.ups && reply.ups.length || 0;
            });
            allUpCount = _.sortBy(allUpCount, Number).reverse();

            var threshold = allUpCount[2] || 0;
            if (threshold < 3) {
                threshold = 3;
            }
            return threshold;
        })();

        ep.emit('topic', topic);

        // get other_topics
        var options = {limit: 5, sort: '-last_reply_at'};
        var query = {author: topic.author, type:'text', _id: {'$nin': [topic._id]}};
        Topic.getTopicsByQuery(query, options, ep.done('other_topics'));

        // get no_reply_topics
        cache.get('no_reply_topics', ep.done(function (no_reply_topics) {
            if (no_reply_topics) {
                ep.emit('no_reply_topics', no_reply_topics);
            } else {
                Topic.getTopicsByQuery(
                    {reply_count: 0, _id: {'$nin': [topic._id]}, type: 'text'},
                    {limit: 5, sort: '-create_at'},
                    ep.done('no_reply_topics', function (no_reply_topics) {
                        let cacheNRT = [];
                        for (let i = 0; i < no_reply_topics.length; i++) {
                            let aurl = no_reply_topics[i].author.avatar_url;
                            let nrtObject = no_reply_topics[i].toObject();
                            nrtObject.author.avatar_url = aurl;
                            cacheNRT.push(nrtObject);
                        }
                        cache.set('no_reply_topics', cacheNRT, 60 * 1);
                        return cacheNRT;
                    }));
            }
        }));
    }));

    if (!currentUser) {
        ep.emit('is_collect', null);
    } else {
        TopicCollect.getTopicCollect(currentUser._id, topic_id, ep.done('is_collect'));
    }
};

exports.create = function (req, res, next) {
    Forum.getForumsByQuery({type : {$ne: 'private'}}, {}, function (err, forums) {
        res.render('topic/edit', {
            tabs: config.tabs,
            forums: forums
        });
    });
};


exports.put = function (req, res, next) {
    var title = validator.trim(req.body.title);
    var forum = req.body.forum;
    var content = validator.trim(req.body.t_content);
    // 验证
    var editError;
    if (title === '') {
        editError = '标题不能是空的。';
    } else if (title.length < 5 || title.length > 100) {
        editError = '标题字数太多或太少。';
    } else if (!forum) {
        editError = '必须选择一个版块。';
    } else if (content === '') {
        editError = '内容不可为空';
    }
    // END 验证

    if (editError) {
        res.status(422);
        Forum.getForumsByQuery({type : {$ne: 'private'}}, {}, function (err, forums) {
            return res.render('topic/edit', {
                edit_error: editError,
                title: title,
                content: content,
                forums: forums
            });
        });
    } else {
        var client_info = tools.client_info(req);
        Topic.newAndSave(title, content, forum, req.session.user._id, client_info, function (err, topic) {
            if (err) {
                return next(err);
            }

            var proxy = new EventProxy();

            proxy.all('score_saved', 'forum_topic_count_added', function () {
                res.redirect('/topic/' + topic._id);
            });

            proxy.fail(next);

            User.getUserById(req.session.user._id, proxy.done(function (user) {
                user.score += 5;
                user.topic_count += 1;
                user.save();
                req.session.user = user;
                proxy.emit('score_saved');
            }));

            Forum.getForum(forum, proxy.done(function (forumObj) {
                forumObj.topic_count += 1;
                forumObj.save();
                proxy.emit('forum_topic_count_added');
            }));

            //发送at消息
            at.sendMessageToMentionUsers(content, topic._id, req.session.user._id);
        });
    }
};

exports.showEdit = function (req, res, next) {
    var topic_id = req.params.tid;

    Topic.getTopicById(topic_id, function (err, topic, tags) {
        if (!topic) {
            res.render404('此话题不存在或已被删除。');
            return;
        }

        if (String(topic.author) === String(req.session.user._id) || req.session.user.is_admin) {
            Forum.getForumsByQuery({type : {$ne: 'private'}}, {}, function (err, forums) {
                res.render('topic/edit', {
                    action: 'edit',
                    topic_id: topic._id,
                    title: topic.title,
                    content: topic.content,
                    tab: topic.forum.toString(),
                    tabs: config.tabs,
                    forums: forums
                });
            });

        } else {
            res.renderError('对不起,你不能编辑此话题。', 403);
        }
    });
};

exports.update = function (req, res, next) {
    var topic_id = req.params.tid;
    var title = req.body.title;
    var forum = req.body.forum;
    var content = req.body.t_content;

    Topic.getTopicById(topic_id, function (err, topic, tags) {
        if (!topic) {
            res.render404('此话题不存在或已被删除。');
            return;
        }

        if (topic.author.equals(req.session.user._id) || req.session.user.is_admin) {
            title = validator.trim(title);
            forum = validator.trim(forum);
            content = validator.trim(content);

            // 验证
            var editError;
            if (title === '') {
                editError = '标题不能是空的。';
            } else if (title.length < 5 || title.length > 100) {
                editError = '标题字数太多或太少。';
            } else if (!forum) {
                editError = '必须选择一个版块。';
            }
            // END 验证

            if (editError) {
                Forum.getForumsByQuery({type : {$ne: 'private'}}, {}, function (err, forums) {
                    return res.render('topic/edit', {
                        action: 'edit',
                        edit_error: editError,
                        topic_id: topic._id,
                        content: content,
                        forums: forums
                    });
                });
            } else {

                //保存话题
                topic.title = title;
                topic.content = content;
                topic.forum = forum;
                topic.update_at = new Date();

                topic.save(function (err) {
                    if (err) {
                        return next(err);
                    }
                    //发送at消息
                    at.sendMessageToMentionUsers(content, topic._id, req.session.user._id);

                    res.redirect('/topic/' + topic._id);

                });
            }
        } else {
            res.renderError('对不起,你不能编辑此话题。', 403);
        }
    });
};

exports.delete = function (req, res, next) {
    //删除话题, 话题作者topic_count减1
    //删除回复,回复作者reply_count减1
    //删除topic_collect,用户collect_topic_count减1

    var topic_id = req.params.tid;

    Topic.getFullTopic(topic_id, function (err, err_msg, topic, author, replies) {
        if (err) {
            return res.send({success: false, message: err.message});
        }
        if (!req.session.user.is_admin && !(topic.author.equals(req.session.user._id))) {
            res.status(403);
            return res.send({success: false, message: '无权限'});
        }
        if (!topic) {
            res.status(422);
            return res.send({success: false, message: '此话题不存在或已被删除。'});
        }
        author.score -= 5;
        author.topic_count -= 1;
        author.save();

        topic.forum.topic_count -= 1;
        topic.forum.save();

        topic.deleted = true;
        topic.save(function (err) {
            if (err) {
                return res.send({success: false, message: err.message});
            }
            res.send({success: true, message: '话题已被删除。'});
        });
    });
};

// 设为置顶
exports.top = function (req, res, next) {
    var topic_id = req.params.tid;
    var referer = req.get('referer');

    if (topic_id.length !== 24) {
        res.render404('此话题不存在或已被删除。');
        return;
    }
    Topic.getTopic(topic_id, function (err, topic) {
        if (err) {
            return next(err);
        }
        if (!topic) {
            res.render404('此话题不存在或已被删除。');
            return;
        }
        topic.top = !topic.top;
        topic.save(function (err) {
            if (err) {
                return next(err);
            }
            var msg = topic.top ? '此话题已置顶。' : '此话题已取消置顶。';
            res.render('notify/notify', {success: msg, referer: referer});
        });
    });
};

// 设为精华
exports.good = function (req, res, next) {
    var topicId = req.params.tid;
    var referer = req.get('referer');

    Topic.getTopic(topicId, function (err, topic) {
        if (err) {
            return next(err);
        }
        if (!topic) {
            res.render404('此话题不存在或已被删除。');
            return;
        }
        topic.good = !topic.good;
        topic.save(function (err) {
            if (err) {
                return next(err);
            }
            var msg = topic.good ? '此话题已加精。' : '此话题已取消加精。';
            res.render('notify/notify', {success: msg, referer: referer});
        });
    });
};

// 锁定主题,不可再回复
exports.lock = function (req, res, next) {
    var topicId = req.params.tid;
    var referer = req.get('referer');
    Topic.getTopic(topicId, function (err, topic) {
        if (err) {
            return next(err);
        }
        if (!topic) {
            res.render404('此话题不存在或已被删除。');
            return;
        }
        topic.lock = !topic.lock;
        topic.save(function (err) {
            if (err) {
                return next(err);
            }
            var msg = topic.lock ? '此话题已锁定。' : '此话题已取消锁定。';
            res.render('notify/notify', {success: msg, referer: referer});
        });
    });
};

// 收藏主题
exports.collect = function (req, res, next) {
    var topic_id = req.body.topic_id;

    Topic.getTopic(topic_id, function (err, topic) {
        if (err) {
            return next(err);
        }
        if (!topic) {
            res.json({status: 'failed'});
        }

        TopicCollect.getTopicCollect(req.session.user._id, topic._id, function (err, doc) {
            if (err) {
                return next(err);
            }
            if (doc) {
                res.json({status: 'failed'});
                return;
            }

            TopicCollect.newAndSave(req.session.user._id, topic._id, function (err) {
                if (err) {
                    return next(err);
                }
                res.json({status: 'success'});
            });
            User.getUserById(req.session.user._id, function (err, user) {
                if (err) {
                    return next(err);
                }
                user.collect_topic_count += 1;
                user.save();
            });

            req.session.user.collect_topic_count += 1;
            topic.collect_count += 1;
            topic.save();
        });
    });
};

exports.de_collect = function (req, res, next) {
    var topic_id = req.body.topic_id;
    Topic.getTopic(topic_id, function (err, topic) {
        if (err) {
            return next(err);
        }
        if (!topic) {
            res.json({status: 'failed'});
        }
        TopicCollect.remove(req.session.user._id, topic._id, function (err, removeResult) {
            if (err) {
                return next(err);
            }
            if (removeResult.result.n === 0) {
                return res.json({status: 'failed'});
            }

            User.getUserById(req.session.user._id, function (err, user) {
                if (err) {
                    return next(err);
                }
                user.collect_topic_count -= 1;
                req.session.user = user;
                user.save();
            });

            topic.collect_count -= 1;
            topic.save();

            res.json({status: 'success'});
        });
    });
};

exports.upload = function (req, res, next) {
    var isFileLimit = false;
    req.busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
        file.on('limit', function () {
            isFileLimit = true;

            res.json({
                success: false,
                msg: 'File size too large. Max is ' + config.file_limit
            });
        });

        store.upload(file, {filename: filename}, function (err, result) {
            if (err) {
                return next(err);
            }
            if (isFileLimit) {
                return;
            }
            res.json({
                success: true,
                url: result.url,
            });
        });

    });

    req.pipe(req.busboy);
};