| Line | Hits | Source |
|---|---|---|
| 1 | /*! | |
| 2 | * nodeclub - app.js | |
| 3 | */ | |
| 4 | ||
| 5 | /** | |
| 6 | * Module dependencies. | |
| 7 | */ | |
| 8 | ||
| 9 | 1 | var path = require('path'); |
| 10 | 1 | var connect = require('connect'); |
| 11 | 1 | var urlrouter = require('urlrouter'); |
| 12 | 1 | var render = require('connect-render'); |
| 13 | 1 | var onehost = require('onehost'); |
| 14 | ||
| 15 | 1 | var config = require('./conf'); |
| 16 | 1 | var routes = require('./routes'); |
| 17 | ||
| 18 | 1 | var app = connect( |
| 19 | connect.cookieParser(), | |
| 20 | connect.session({ | |
| 21 | secret: config.session_secret | |
| 22 | }), | |
| 23 | connect.csrf(), | |
| 24 | render({ | |
| 25 | root: path.join(__dirname, 'views'), | |
| 26 | layout: 'layout.html', | |
| 27 | cache: config.debug, // `false` for debug | |
| 28 | helpers: { | |
| 29 | config: config, | |
| 30 | sitename: 'connect-render demo site', | |
| 31 | starttime: new Date(), | |
| 32 | _csrf: function (req, res) { | |
| 33 | 1 | return req.session._csrf; |
| 34 | }, | |
| 35 | now: function (req, res) { | |
| 36 | 1 | return new Date(); |
| 37 | } | |
| 38 | } | |
| 39 | }) | |
| 40 | ); | |
| 41 | ||
| 42 | /** | |
| 43 | * Static files | |
| 44 | */ | |
| 45 | ||
| 46 | 1 | app.use('/public', connect.static(path.join(__dirname, 'public'))); |
| 47 | ||
| 48 | /** | |
| 49 | * URL Routing | |
| 50 | */ | |
| 51 | 1 | app.use(urlrouter(routes)); |
| 52 | ||
| 53 | /** | |
| 54 | * One host binding | |
| 55 | */ | |
| 56 | ||
| 57 | 1 | if (config.onehost) { |
| 58 | 0 | onehost({ |
| 59 | host: config.hostname | |
| 60 | }); | |
| 61 | } | |
| 62 | ||
| 63 | 1 | if (process.env.NODE_ENV !== 'test') { |
| 64 | // plugins | |
| 65 | 0 | var plugins = config.plugins || []; |
| 66 | 0 | for (var i = 0, l = plugins.length; i < l; i++) { |
| 67 | 0 | var p = plugins[i]; |
| 68 | 0 | app.use(require('./plugins/' + p.name)(p.options)); |
| 69 | } | |
| 70 | } | |
| 71 | ||
| 72 | 1 | var maxAge = 3600000 * 24 * 30; |
| 73 | // app.use('/upload/', express.static(config.upload_dir, { maxAge: maxAge })); | |
| 74 | // // old image url: http://host/user_data/images/xxxx | |
| 75 | // app.use('/user_data/', express.static(path.join(__dirname, 'public', 'user_data'), { maxAge: maxAge })); | |
| 76 | ||
| 77 | // var staticDir = path.join(__dirname, 'public'); | |
| 78 | // app.configure('development', function () { | |
| 79 | // app.use(express.static(staticDir)); | |
| 80 | // app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); | |
| 81 | // }); | |
| 82 | ||
| 83 | // app.configure('production', function () { | |
| 84 | // app.use(express.static(staticDir, { maxAge: maxAge })); | |
| 85 | // app.use(express.errorHandler()); | |
| 86 | // app.set('view cache', true); | |
| 87 | // }); | |
| 88 | ||
| 89 | ||
| 90 | 1 | if (process.env.NODE_ENV !== 'test') { |
| 91 | 0 | app.listen(config.port); |
| 92 | ||
| 93 | 0 | console.log("NodeClub listening on port %d", config.port); |
| 94 | 0 | console.log("God bless love...."); |
| 95 | 0 | console.log("You can debug your app with http://" + config.hostname + ':' + config.port); |
| 96 | } | |
| 97 | ||
| 98 | 1 | module.exports = app; |
| Line | Hits | Source |
|---|---|---|
| 1 | /*! | |
| 2 | * nodeclub - conf/index.js | |
| 3 | * Copyright(c) 2012 fengmk2 <fengmk2@gmail.com> | |
| 4 | * MIT Licensed | |
| 5 | */ | |
| 6 | ||
| 7 | 1 | "use strict"; |
| 8 | ||
| 9 | /** | |
| 10 | * Module dependencies. | |
| 11 | */ | |
| 12 | ||
| 13 | 1 | var path = require('path'); |
| 14 | 1 | var fs = require('fs'); |
| 15 | 1 | fs.existsSync = fs.existsSync || path.existsSync; |
| 16 | ||
| 17 | 1 | var settings = { |
| 18 | debug: true, | |
| 19 | name: 'NodeClub', | |
| 20 | version: '0.2.2', | |
| 21 | ||
| 22 | // site settings | |
| 23 | site_headers: [ | |
| 24 | '<meta name="author" content="EDP@TAOBAO" />', | |
| 25 | ], | |
| 26 | host: 'localhost.cnodejs.org', | |
| 27 | port: 3000, | |
| 28 | site_logo: '', // default is `name` | |
| 29 | site_navs: [ | |
| 30 | // [ path, title, [target=''] ] | |
| 31 | [ '/about', '关于' ], | |
| 32 | ], | |
| 33 | site_static_host: '/public', // 静态文件存储域名 | |
| 34 | site_enable_search_preview: false, // 开启google search preview | |
| 35 | site_google_search_domain: 'cnodejs.org', // google search preview中要搜索的域名 | |
| 36 | ||
| 37 | upload_dir: path.join(__dirname, 'public', 'user_data', 'images'), | |
| 38 | ||
| 39 | db: 'mongodb://127.0.0.1/node_club_dev', | |
| 40 | session_secret: 'node_club', | |
| 41 | auth_cookie_name: 'node_club', | |
| 42 | ||
| 43 | // 话题列表显示的话题数量 | |
| 44 | list_topic_count: 20, | |
| 45 | ||
| 46 | // RSS | |
| 47 | rss: { | |
| 48 | title: 'CNode:Node.js专业中文社区', | |
| 49 | link: 'http://cnodejs.org', | |
| 50 | language: 'zh-cn', | |
| 51 | description: 'CNode:Node.js专业中文社区', | |
| 52 | ||
| 53 | //最多获取的RSS Item数量 | |
| 54 | max_rss_items: 50 | |
| 55 | }, | |
| 56 | ||
| 57 | // site links | |
| 58 | site_links: [ | |
| 59 | { | |
| 60 | 'text': 'Node 官方网站', | |
| 61 | 'url': 'http://nodejs.org/' | |
| 62 | }, | |
| 63 | { | |
| 64 | 'text': 'Node Party', | |
| 65 | 'url': 'http://party.cnodejs.net/' | |
| 66 | }, | |
| 67 | { | |
| 68 | 'text': 'Node 入门', | |
| 69 | 'url': 'http://nodebeginner.org/index-zh-cn.html' | |
| 70 | }, | |
| 71 | { | |
| 72 | 'text': 'Node 中文文档', | |
| 73 | 'url': 'http://docs.cnodejs.net/cman/' | |
| 74 | } | |
| 75 | ], | |
| 76 | ||
| 77 | // sidebar ads | |
| 78 | side_ads: [ | |
| 79 | { | |
| 80 | 'url': 'http://www.upyun.com/?utm_source=nodejs&utm_medium=link&utm_campaign=upyun&md=nodejs', | |
| 81 | 'image': 'http://site-cnode.b0.upaiyun.com/images/upyun_logo.png', | |
| 82 | 'text': '' | |
| 83 | }, | |
| 84 | { | |
| 85 | 'url': 'http://ruby-china.org/?utm_source=nodejs&utm_medium=link&utm_campaign=upyun&md=nodejs', | |
| 86 | 'image': 'http://site-cnode.b0.upaiyun.com/images/ruby_china_logo.png', | |
| 87 | 'text': '' | |
| 88 | }, | |
| 89 | { | |
| 90 | 'url': 'http://adc.taobao.com/', | |
| 91 | 'image': 'http://adc.taobao.com/bundles/devcarnival/images/d2_180x250.jpg', | |
| 92 | 'text': '' | |
| 93 | } | |
| 94 | ], | |
| 95 | ||
| 96 | // mail SMTP | |
| 97 | mail_port: 25, | |
| 98 | mail_user: 'club', | |
| 99 | mail_pass: 'club', | |
| 100 | mail_host: 'smtp.126.com', | |
| 101 | mail_sender: 'club@126.com', | |
| 102 | mail_use_authentication: true, | |
| 103 | ||
| 104 | //weibo app key | |
| 105 | weibo_key: 10000000, | |
| 106 | ||
| 107 | // admin 可删除话题,编辑标签,设某人为达人 | |
| 108 | admins: { admin: true }, | |
| 109 | ||
| 110 | // [ { name: 'plugin_name', options: { ... }, ... ] | |
| 111 | plugins: [ | |
| 112 | // { name: 'onehost', options: { host: 'localhost.cnodejs.org' } }, | |
| 113 | // { name: 'wordpress_redirect', options: {} } | |
| 114 | ] | |
| 115 | }; | |
| 116 | ||
| 117 | /** | |
| 118 | * Loading custom settings | |
| 119 | */ | |
| 120 | ||
| 121 | 1 | var configPath = path.join(__dirname, 'config.js'); |
| 122 | 1 | if (fs.existsSync(configPath)) { |
| 123 | 0 | var config = require('configPath'); |
| 124 | 0 | for (var k in config) { |
| 125 | 0 | settings[k] = config[k]; |
| 126 | } | |
| 127 | } | |
| 128 | ||
| 129 | // host: http://127.0.0.1 | |
| 130 | 1 | var urlinfo = require('url').parse(settings.host); |
| 131 | 1 | settings.hostname = urlinfo.hostname || settings.host; |
| 132 | ||
| 133 | 1 | module.exports = settings; |
| Line | Hits | Source |
|---|---|---|
| 1 | /*! | |
| 2 | * nodeclub - route.js | |
| 3 | * Copyright(c) 2012 fengmk2 <fengmk2@gmail.com> | |
| 4 | * MIT Licensed | |
| 5 | */ | |
| 6 | ||
| 7 | /** | |
| 8 | * Module dependencies. | |
| 9 | */ | |
| 10 | ||
| 11 | 1 | var home = require('./controllers/home'); |
| 12 | 1 | var sign = require('./controllers/sign'); |
| 13 | 1 | var site = require('./controllers/site'); |
| 14 | 1 | var user = require('./controllers/user'); |
| 15 | 1 | var message = require('./controllers/message'); |
| 16 | 1 | var tag = require('./controllers/tag'); |
| 17 | 1 | var topic = require('./controllers/topic'); |
| 18 | 1 | var reply = require('./controllers/reply'); |
| 19 | 1 | var rss = require('./controllers/rss'); |
| 20 | 1 | var upload = require('./controllers/upload'); |
| 21 | 1 | var static = require('./controllers/static'); |
| 22 | 1 | var tools = require('./controllers/tools'); |
| 23 | // var status = require('./controllers/status'); | |
| 24 | ||
| 25 | 1 | module.exports = function routes(app) { |
| 26 | // home page | |
| 27 | 1 | app.get('/', home); |
| 28 | ||
| 29 | // sign up, login, logout | |
| 30 | 1 | app.get('/signup', sign.signup); |
| 31 | 1 | app.post('/signup', sign.signup); |
| 32 | 1 | app.get('/signout', sign.signout); |
| 33 | 1 | app.get('/signin', sign.showLogin); |
| 34 | 1 | app.post('/signin', sign.login); |
| 35 | 1 | app.get('/active_account', sign.active_account); |
| 36 | ||
| 37 | // password | |
| 38 | 1 | app.get('/search_pass', sign.search_pass); |
| 39 | 1 | app.post('/search_pass', sign.search_pass); |
| 40 | 1 | app.get('/reset_pass', sign.reset_pass); |
| 41 | 1 | app.post('/reset_pass', sign.reset_pass); |
| 42 | ||
| 43 | // user | |
| 44 | 1 | app.get('/user/:name', user.index); |
| 45 | 1 | app.get('/setting', user.setting); |
| 46 | 1 | app.post('/setting', user.setting); |
| 47 | 1 | app.get('/stars', user.show_stars); |
| 48 | 1 | app.get('/users/top100', user.top100); |
| 49 | 1 | app.get('/my/tags', user.get_collect_tags); |
| 50 | 1 | app.get('/my/topics', user.get_collect_topics); |
| 51 | 1 | app.get('/my/messages', message.index); |
| 52 | 1 | app.get('/my/follower', user.get_followers); |
| 53 | 1 | app.get('/my/following', user.get_followings); |
| 54 | 1 | app.get('/user/:name/topics', user.list_topics); |
| 55 | 1 | app.get('/user/:name/replies', user.list_replies); |
| 56 | 1 | app.post('/user/follow', user.follow); |
| 57 | 1 | app.post('/user/un_follow', user.un_follow); |
| 58 | 1 | app.post('/user/set_star', user.toggle_star); |
| 59 | 1 | app.post('/user/cancel_star', user.toggle_star); |
| 60 | ||
| 61 | // message | |
| 62 | 1 | app.post('/messages/mark_read', message.mark_read); |
| 63 | 1 | app.post('/messages/mark_all_read', message.mark_all_read); |
| 64 | ||
| 65 | // tag | |
| 66 | 1 | app.get('/tags/edit', tag.edit_tags); |
| 67 | 1 | app.get('/tag/:name', tag.list_topic); |
| 68 | 1 | app.get('/tag/:name/edit', tag.edit); |
| 69 | 1 | app.get('/tag/:name/delete', tag.delete); |
| 70 | 1 | app.post('/tag/add', tag.add); |
| 71 | 1 | app.post('/tag/:name/edit', tag.edit); |
| 72 | 1 | app.post('/tag/collect', tag.collect); |
| 73 | 1 | app.post('/tag/de_collect', tag.de_collect); |
| 74 | ||
| 75 | // topic | |
| 76 | 1 | app.get('/topic/create', topic.create); |
| 77 | 1 | app.get('/topic/:tid', topic.index); |
| 78 | 1 | app.get('/topic/:tid/top/:is_top?', topic.top); |
| 79 | 1 | app.get('/topic/:tid/edit', topic.edit); |
| 80 | 1 | app.get('/topic/:tid/delete', topic.delete); |
| 81 | 1 | app.post('/topic/create', topic.create); |
| 82 | 1 | app.post('/topic/:tid/edit', topic.edit); |
| 83 | 1 | app.post('/topic/collect', topic.collect); |
| 84 | 1 | app.post('/topic/de_collect', topic.de_collect); |
| 85 | ||
| 86 | // reply | |
| 87 | 1 | app.post('/:topic_id/reply', reply.add); |
| 88 | 1 | app.post('/:topic_id/reply2', reply.add_reply2); |
| 89 | 1 | app.post('/reply/:reply_id/delete', reply.delete); |
| 90 | ||
| 91 | // upload | |
| 92 | 1 | app.post('/upload/image', upload.uploadImage); |
| 93 | ||
| 94 | // tools | |
| 95 | 1 | app.get('/site_tools', tools.run_site_tools); |
| 96 | ||
| 97 | // static | |
| 98 | 1 | app.get('/about', static.about); |
| 99 | 1 | app.get('/faq', static.faq); |
| 100 | ||
| 101 | //rss | |
| 102 | 1 | app.get('/rss', rss.index); |
| 103 | ||
| 104 | // site status | |
| 105 | // app.get('/status', status.status); | |
| 106 | }; |
| Line | Hits | Source |
|---|---|---|
| 1 | /*! | |
| 2 | * nodeclub - controllers/home.js | |
| 3 | * Copyright(c) 2012 fengmk2 <fengmk2@gmail.com> | |
| 4 | * MIT Licensed | |
| 5 | */ | |
| 6 | ||
| 7 | 1 | "use strict"; |
| 8 | ||
| 9 | /** | |
| 10 | * Module dependencies. | |
| 11 | */ | |
| 12 | ||
| 13 | 1 | module.exports = function (req, res, next) { |
| 14 | 1 | res.render('index.html'); |
| 15 | }; |
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | var models = require('../models'); |
| 2 | 1 | var User = models.User; |
| 3 | ||
| 4 | 1 | var check = require('validator').check; |
| 5 | 1 | var sanitize = require('validator').sanitize; |
| 6 | ||
| 7 | 1 | var crypto = require('crypto'); |
| 8 | 1 | var config = require('../conf'); |
| 9 | ||
| 10 | 1 | var message_ctrl = require('./message'); |
| 11 | 1 | var mail_ctrl = require('./mail'); |
| 12 | ||
| 13 | //sign up | |
| 14 | 1 | exports.signup = function(req,res,next){ |
| 15 | 0 | var method = req.method.toLowerCase(); |
| 16 | 0 | if (method === 'get'){ |
| 17 | 0 | res.render('sign/signup'); |
| 18 | 0 | return; |
| 19 | } | |
| 20 | 0 | if(method === 'post'){ |
| 21 | 0 | var name = sanitize(req.body.name).trim(); |
| 22 | 0 | name = sanitize(name).xss(); |
| 23 | 0 | var loginname = name.toLowerCase(); |
| 24 | 0 | var pass = sanitize(req.body.pass).trim(); |
| 25 | 0 | pass = sanitize(pass).xss(); |
| 26 | 0 | var email = sanitize(req.body.email).trim(); |
| 27 | 0 | email = email.toLowerCase(); |
| 28 | 0 | email = sanitize(email).xss(); |
| 29 | 0 | var re_pass = sanitize(req.body.re_pass).trim(); |
| 30 | 0 | re_pass = sanitize(re_pass).xss(); |
| 31 | ||
| 32 | 0 | if(name == '' || pass =='' || re_pass == '' || email ==''){ |
| 33 | 0 | res.render('sign/signup', {error:'信息不完整。',name:name,email:email}); |
| 34 | 0 | return; |
| 35 | } | |
| 36 | ||
| 37 | 0 | if(name.length < 5){ |
| 38 | 0 | res.render('sign/signup', {error:'用户名至少需要5个字符。',name:name,email:email}); |
| 39 | 0 | return; |
| 40 | } | |
| 41 | ||
| 42 | 0 | try{ |
| 43 | 0 | check(name, '用户名只能使用0-9,a-z,A-Z。').isAlphanumeric(); |
| 44 | }catch(e){ | |
| 45 | 0 | res.render('sign/signup', {error:e.message,name:name,email:email}); |
| 46 | 0 | return; |
| 47 | } | |
| 48 | ||
| 49 | 0 | if(pass != re_pass){ |
| 50 | 0 | res.render('sign/signup', {error:'两次密码输入不一致。',name:name,email:email}); |
| 51 | 0 | return; |
| 52 | } | |
| 53 | ||
| 54 | 0 | try{ |
| 55 | 0 | check(email, '不正确的电子邮箱。').isEmail(); |
| 56 | }catch(e){ | |
| 57 | 0 | res.render('sign/signup', {error:e.message,name:name,email:email}); |
| 58 | 0 | return; |
| 59 | } | |
| 60 | ||
| 61 | 0 | User.find({'$or':[{'loginname':loginname},{'email':email}]},function(err,users){ |
| 62 | 0 | if(err) return next(err); |
| 63 | 0 | if(users.length > 0){ |
| 64 | 0 | res.render('sign/signup', {error:'用户名或邮箱已被使用。',name:name,email:email}); |
| 65 | 0 | return; |
| 66 | } | |
| 67 | ||
| 68 | // md5 the pass | |
| 69 | 0 | pass = md5(pass); |
| 70 | // create gavatar | |
| 71 | 0 | var avatar_url = 'http://www.gravatar.com/avatar/' + md5(email) + '?size=48'; |
| 72 | ||
| 73 | 0 | var user = new User(); |
| 74 | 0 | user.name = name; |
| 75 | 0 | user.loginname = loginname; |
| 76 | 0 | user.pass = pass; |
| 77 | 0 | user.email = email; |
| 78 | 0 | user.avatar = avatar_url; |
| 79 | 0 | user.active = false; |
| 80 | 0 | user.save(function(err){ |
| 81 | 0 | if (err) { |
| 82 | 0 | return next(err); |
| 83 | } | |
| 84 | 0 | mail_ctrl.send_active_mail(email,md5(email + config.session_secret), name,email,function(err,success){ |
| 85 | 0 | if(success){ |
| 86 | 0 | res.render('sign/signup', {success:'欢迎加入 ' + config.name + '!我们已给您的注册邮箱发送了一封邮件,请点击里面的链接来激活您的帐号。'}); |
| 87 | 0 | return; |
| 88 | } | |
| 89 | }); | |
| 90 | }); | |
| 91 | }); | |
| 92 | } | |
| 93 | }; | |
| 94 | ||
| 95 | /** | |
| 96 | * Show user login page. | |
| 97 | * | |
| 98 | * @param {HttpRequest} req | |
| 99 | * @param {HttpResponse} res | |
| 100 | */ | |
| 101 | 1 | exports.showLogin = function(req, res) { |
| 102 | 0 | req.session._loginReferer = req.headers.referer; |
| 103 | 0 | res.render('sign/signin'); |
| 104 | }; | |
| 105 | /** | |
| 106 | * define some page when login just jump to the home page | |
| 107 | * @type {Array} | |
| 108 | */ | |
| 109 | 1 | var notJump = [ |
| 110 | '/active_account', //active page | |
| 111 | '/reset_pass', //reset password page, avoid to reset twice | |
| 112 | '/signup', //regist page | |
| 113 | '/search_pass' //serch pass page | |
| 114 | ]; | |
| 115 | /** | |
| 116 | * Handle user login. | |
| 117 | * | |
| 118 | * @param {HttpRequest} req | |
| 119 | * @param {HttpResponse} res | |
| 120 | * @param {Function} next | |
| 121 | */ | |
| 122 | 1 | exports.login = function(req, res, next) { |
| 123 | 0 | var loginname = sanitize(req.body.name).trim().toLowerCase(); |
| 124 | 0 | var pass = sanitize(req.body.pass).trim(); |
| 125 | ||
| 126 | 0 | if (!loginname || !pass) { |
| 127 | 0 | return res.render('sign/signin', { error: '信息不完整。' }); |
| 128 | } | |
| 129 | ||
| 130 | 0 | User.findOne({ 'loginname': loginname }, function (err, user) { |
| 131 | 0 | if (err) return next(err); |
| 132 | 0 | if (!user) { |
| 133 | 0 | return res.render('sign/signin', { error:'这个用户不存在。' }); |
| 134 | } | |
| 135 | 0 | pass = md5(pass); |
| 136 | 0 | if (pass !== user.pass) { |
| 137 | 0 | return res.render('sign/signin', { error:'密码错误。' }); |
| 138 | } | |
| 139 | 0 | if (!user.active) { |
| 140 | 0 | res.render('sign/signin', { error:'此帐号还没有被激活。' }); |
| 141 | 0 | return; |
| 142 | } | |
| 143 | // store session cookie | |
| 144 | 0 | gen_session(user, res); |
| 145 | //check at some page just jump to home page | |
| 146 | 0 | var refer = req.session._loginReferer || 'home'; |
| 147 | 0 | for (var i=0, len=notJump.length; i!=len; ++i) { |
| 148 | 0 | if (refer.indexOf(notJump[i]) >= 0) { |
| 149 | 0 | refer = 'home'; |
| 150 | 0 | break; |
| 151 | } | |
| 152 | } | |
| 153 | 0 | res.redirect(refer); |
| 154 | }); | |
| 155 | }; | |
| 156 | ||
| 157 | // sign out | |
| 158 | 1 | exports.signout = function(req, res, next) { |
| 159 | 0 | req.session.destroy(); |
| 160 | 0 | res.clearCookie(config.auth_cookie_name, { path: '/' }); |
| 161 | 0 | res.redirect(req.headers.referer || 'home'); |
| 162 | }; | |
| 163 | ||
| 164 | 1 | exports.active_account = function(req,res,next) { |
| 165 | 0 | var key = req.query.key; |
| 166 | 0 | var name = req.query.name; |
| 167 | 0 | var email = req.query.email; |
| 168 | ||
| 169 | 0 | User.findOne({name:name},function(err,user){ |
| 170 | 0 | if(!user || md5(email+config.session_secret) != key){ |
| 171 | 0 | res.render('notify/notify',{error: '信息有误,帐号无法被激活。'}); |
| 172 | 0 | return; |
| 173 | } | |
| 174 | 0 | if(user.active){ |
| 175 | 0 | res.render('notify/notify',{error: '帐号已经是激活状态。'}); |
| 176 | 0 | return; |
| 177 | } | |
| 178 | 0 | user.active = true; |
| 179 | 0 | user.save(function(err){ |
| 180 | 0 | res.render('notify/notify',{success: '帐号已被激活,请登录'}); |
| 181 | }); | |
| 182 | }); | |
| 183 | } | |
| 184 | ||
| 185 | 1 | exports.search_pass = function(req,res,next){ |
| 186 | 0 | var method = req.method.toLowerCase(); |
| 187 | 0 | if(method == 'get'){ |
| 188 | 0 | res.render('sign/search_pass'); |
| 189 | } | |
| 190 | 0 | if(method == 'post'){ |
| 191 | 0 | var email = req.body.email; |
| 192 | 0 | email = email.toLowerCase(); |
| 193 | ||
| 194 | 0 | try{ |
| 195 | 0 | check(email, '不正确的电子邮箱。').isEmail(); |
| 196 | }catch(e){ | |
| 197 | 0 | res.render('sign/search_pass', {error:e.message,email:email}); |
| 198 | 0 | return; |
| 199 | } | |
| 200 | ||
| 201 | // User.findOne({email:email},function(err,user){ | |
| 202 | //动态生成retrive_key和timestamp到users collection,之后重置密码进行验证 | |
| 203 | 0 | var retrieveKey = randomString(15); |
| 204 | 0 | var retrieveTime = new Date().getTime(); |
| 205 | 0 | User.findOne({email : email}, function(err, user) { |
| 206 | 0 | if(!user) { |
| 207 | 0 | res.render('sign/search_pass', {error:'没有这个电子邮箱。',email:email}); |
| 208 | 0 | return; |
| 209 | } | |
| 210 | 0 | user.retrieve_key = retrieveKey; |
| 211 | 0 | user.retrieve_time = retrieveTime; |
| 212 | 0 | user.save(function(err) { |
| 213 | 0 | if(err) { |
| 214 | 0 | return next(err); |
| 215 | } | |
| 216 | 0 | mail_ctrl.send_reset_pass_mail(email, retrieveKey, user.name, function(err,success) { |
| 217 | 0 | res.render('notify/notify',{success: '我们已给您填写的电子邮箱发送了一封邮件,请在24小时内点击里面的链接来重置密码。'}); |
| 218 | }); | |
| 219 | }); | |
| 220 | }); | |
| 221 | } | |
| 222 | } | |
| 223 | /** | |
| 224 | * reset password | |
| 225 | * 'get' to show the page, 'post' to reset password | |
| 226 | * after reset password, retrieve_key&time will be destroy | |
| 227 | * @param {http.req} req | |
| 228 | * @param {http.res} res | |
| 229 | * @param {Function} next | |
| 230 | */ | |
| 231 | 1 | exports.reset_pass = function(req,res,next) { |
| 232 | 0 | var method = req.method.toLowerCase(); |
| 233 | 0 | if(method === 'get') { |
| 234 | 0 | var key = req.query.key; |
| 235 | 0 | var name = req.query.name; |
| 236 | 0 | User.findOne({name:name, retrieve_key:key},function(err,user) { |
| 237 | 0 | if(!user) { |
| 238 | 0 | return res.render('notify/notify',{error: '信息有误,密码无法重置。'}); |
| 239 | } | |
| 240 | 0 | var now = new Date().getTime(); |
| 241 | 0 | var oneDay = 1000 * 60 * 60 * 24; |
| 242 | 0 | if(!user.retrieve_time || now - user.retrieve_time > oneDay) { |
| 243 | 0 | return res.render('notify/notify', {error : '该链接已过期,请重新申请。'}); |
| 244 | } | |
| 245 | 0 | return res.render('sign/reset', {name : name, key : key}); |
| 246 | }); | |
| 247 | } else { | |
| 248 | 0 | var psw = req.body.psw || ''; |
| 249 | 0 | var repsw = req.body.repsw || ''; |
| 250 | 0 | var key = req.body.key || ''; |
| 251 | 0 | var name = req.body.name || ''; |
| 252 | 0 | if(psw !== repsw) { |
| 253 | 0 | return res.render('sign/reset', {name : name, key : key, error : '两次密码输入不一致。'}); |
| 254 | } | |
| 255 | 0 | User.findOne({name:name, retrieve_key: key}, function(err, user) { |
| 256 | 0 | if(!user) { |
| 257 | 0 | return res.render('notify/notify', {error : '错误的激活链接'}); |
| 258 | } | |
| 259 | 0 | user.pass = md5(psw); |
| 260 | 0 | user.retrieve_key = null; |
| 261 | 0 | user.retrieve_time = null; |
| 262 | 0 | user.active = true; // 用户激活 |
| 263 | 0 | user.save(function(err) { |
| 264 | 0 | if(err) { |
| 265 | 0 | return next(err); |
| 266 | } | |
| 267 | 0 | return res.render('notify/notify', {success: '你的密码已重置。'}); |
| 268 | }) | |
| 269 | }) | |
| 270 | } | |
| 271 | } | |
| 272 | ||
| 273 | 1 | function getAvatarURL(user) { |
| 274 | 0 | if (user.avatar_url) { |
| 275 | 0 | return user.avatar_url; |
| 276 | } | |
| 277 | 0 | var avatar_url = user.profile_image_url || user.avatar; |
| 278 | 0 | if (!avatar_url) { |
| 279 | 0 | avatar_url = config.site_static_host + '/images/user_icon&48.png'; |
| 280 | } | |
| 281 | 0 | return avatar_url; |
| 282 | } | |
| 283 | ||
| 284 | // auth_user middleware | |
| 285 | 1 | exports.auth_user = function(req, res, next) { |
| 286 | 0 | if (req.session.user) { |
| 287 | 0 | if (config.admins[req.session.user.name]) { |
| 288 | 0 | req.session.user.is_admin = true; |
| 289 | } | |
| 290 | 0 | message_ctrl.get_messages_count(req.session.user._id, function (err, count) { |
| 291 | 0 | if (err) { |
| 292 | 0 | return next(err); |
| 293 | } | |
| 294 | 0 | req.session.user.messages_count = count; |
| 295 | 0 | if (!req.session.user.avatar_url) { |
| 296 | 0 | req.session.user.avatar_url = getAvatarURL(req.session.user); |
| 297 | } | |
| 298 | 0 | res.local('current_user', req.session.user); |
| 299 | 0 | return next(); |
| 300 | }); | |
| 301 | } else { | |
| 302 | 0 | var cookie = req.cookies[config.auth_cookie_name]; |
| 303 | 0 | if (!cookie) return next(); |
| 304 | ||
| 305 | 0 | var auth_token = decrypt(cookie, config.session_secret); |
| 306 | 0 | var auth = auth_token.split('\t'); |
| 307 | 0 | var user_id = auth[0]; |
| 308 | 0 | User.findOne({_id:user_id},function (err,user){ |
| 309 | 0 | if (err) { |
| 310 | 0 | return next(err); |
| 311 | } | |
| 312 | 0 | if (user) { |
| 313 | 0 | if(config.admins[user.name]){ |
| 314 | 0 | user.is_admin = true; |
| 315 | } | |
| 316 | 0 | message_ctrl.get_messages_count(user._id,function(err,count){ |
| 317 | 0 | if(err) return next(err); |
| 318 | 0 | user.messages_count = count; |
| 319 | 0 | req.session.user = user; |
| 320 | 0 | req.session.user.avatar_url = user.avatar_url; |
| 321 | 0 | res.local('current_user',req.session.user); |
| 322 | 0 | return next(); |
| 323 | }); | |
| 324 | }else{ | |
| 325 | 0 | return next(); |
| 326 | } | |
| 327 | }); | |
| 328 | } | |
| 329 | }; | |
| 330 | ||
| 331 | // private | |
| 332 | 1 | function gen_session(user,res) { |
| 333 | 0 | var auth_token = encrypt(user._id + '\t'+user.name + '\t' + user.pass +'\t' + user.email, config.session_secret); |
| 334 | 0 | res.cookie(config.auth_cookie_name, auth_token, {path: '/',maxAge: 1000*60*60*24*30}); //cookie 有效期30天 |
| 335 | } | |
| 336 | 1 | function encrypt(str,secret) { |
| 337 | 0 | var cipher = crypto.createCipher('aes192', secret); |
| 338 | 0 | var enc = cipher.update(str,'utf8','hex'); |
| 339 | 0 | enc += cipher.final('hex'); |
| 340 | 0 | return enc; |
| 341 | } | |
| 342 | 1 | function decrypt(str,secret) { |
| 343 | 0 | var decipher = crypto.createDecipher('aes192', secret); |
| 344 | 0 | var dec = decipher.update(str,'hex','utf8'); |
| 345 | 0 | dec += decipher.final('utf8'); |
| 346 | 0 | return dec; |
| 347 | } | |
| 348 | 1 | function md5(str) { |
| 349 | 0 | var md5sum = crypto.createHash('md5'); |
| 350 | 0 | md5sum.update(str); |
| 351 | 0 | str = md5sum.digest('hex'); |
| 352 | 0 | return str; |
| 353 | } | |
| 354 | 1 | function randomString(size) { |
| 355 | 0 | size = size || 6; |
| 356 | 0 | var code_string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; |
| 357 | 0 | var max_num = code_string.length + 1; |
| 358 | 0 | var new_pass = ''; |
| 359 | 0 | while(size>0){ |
| 360 | 0 | new_pass += code_string.charAt(Math.floor(Math.random()* max_num)); |
| 361 | 0 | size--; |
| 362 | } | |
| 363 | 0 | return new_pass; |
| 364 | } |
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | var mongoose = require('mongoose'); |
| 2 | 1 | var config = require('../conf'); |
| 3 | ||
| 4 | 1 | mongoose.connect(config.db, function (err) { |
| 5 | 1 | if (err) { |
| 6 | 0 | console.error('connect to %s error: ', config.db, err.message); |
| 7 | 0 | process.exit(1); |
| 8 | } | |
| 9 | }); | |
| 10 | ||
| 11 | // models | |
| 12 | 1 | require('./tag'); |
| 13 | 1 | require('./user'); |
| 14 | 1 | require('./topic'); |
| 15 | 1 | require('./topic_tag'); |
| 16 | 1 | require('./reply'); |
| 17 | 1 | require('./topic_collect'); |
| 18 | 1 | require('./tag_collect'); |
| 19 | 1 | require('./relation'); |
| 20 | 1 | require('./message'); |
| 21 | ||
| 22 | 1 | exports.Tag = mongoose.model('Tag'); |
| 23 | 1 | exports.User = mongoose.model('User'); |
| 24 | 1 | exports.Topic = mongoose.model('Topic'); |
| 25 | 1 | exports.TopicTag = mongoose.model('TopicTag'); |
| 26 | 1 | exports.Reply = mongoose.model('Reply'); |
| 27 | 1 | exports.TopicCollect = mongoose.model('TopicCollect'); |
| 28 | 1 | exports.TagCollect = mongoose.model('TagCollect'); |
| 29 | 1 | exports.Relation = mongoose.model('Relation'); |
| 30 | 1 | exports.Message = mongoose.model('Message'); |
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | var mongoose = require('mongoose'); |
| 2 | 1 | var Schema = mongoose.Schema; |
| 3 | ||
| 4 | 1 | var TagSchema = new Schema({ |
| 5 | name: { type: String }, | |
| 6 | order: { type: Number, default: 1 }, | |
| 7 | description: { type: String }, | |
| 8 | background: { type: String }, | |
| 9 | topic_count: { type: Number, default: 0 }, | |
| 10 | collect_count: { type: Number, default: 0 }, | |
| 11 | create_at: { type: Date, default: Date.now } | |
| 12 | }); | |
| 13 | ||
| 14 | 1 | mongoose.model('Tag', TagSchema); |
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | var mongoose = require('mongoose'); |
| 2 | 1 | var Schema = mongoose.Schema; |
| 3 | 1 | var config = require('../conf'); |
| 4 | ||
| 5 | 1 | var UserSchema = new Schema({ |
| 6 | name: { type: String, index: true }, | |
| 7 | loginname: { type: String, unique: true }, | |
| 8 | pass: { type: String }, | |
| 9 | email: { type: String, unique: true }, | |
| 10 | url: { type: String }, | |
| 11 | profile_image_url: {type: String}, | |
| 12 | location: { type: String }, | |
| 13 | signature: { type: String }, | |
| 14 | profile: { type: String }, | |
| 15 | weibo: { type: String }, | |
| 16 | avatar: { type: String }, | |
| 17 | ||
| 18 | score: { type: Number, default: 0 }, | |
| 19 | topic_count: { type: Number, default: 0 }, | |
| 20 | reply_count: { type: Number, default: 0 }, | |
| 21 | follower_count: { type: Number, default: 0 }, | |
| 22 | following_count: { type: Number, default: 0 }, | |
| 23 | collect_tag_count: { type: Number, default: 0 }, | |
| 24 | collect_topic_count: { type: Number, default: 0 }, | |
| 25 | create_at: { type: Date, default: Date.now }, | |
| 26 | update_at: { type: Date, default: Date.now }, | |
| 27 | is_star: { type: Boolean }, | |
| 28 | level: { type: String }, | |
| 29 | active: { type: Boolean, default: true }, | |
| 30 | ||
| 31 | receive_reply_mail: {type: Boolean, default: false }, | |
| 32 | receive_at_mail: { type: Boolean, default: false }, | |
| 33 | from_wp: { type: Boolean }, | |
| 34 | ||
| 35 | retrieve_time : {type: Number}, | |
| 36 | retrieve_key : {type: String} | |
| 37 | }); | |
| 38 | ||
| 39 | 1 | UserSchema.virtual('avatar_url').get(function () { |
| 40 | 0 | var avatar_url = this.profile_image_url || this.avatar; |
| 41 | 0 | if (!avatar_url) { |
| 42 | 0 | avatar_url = config.site_static_host + '/images/user_icon&48.png'; |
| 43 | } | |
| 44 | 0 | return avatar_url; |
| 45 | }); | |
| 46 | ||
| 47 | 1 | mongoose.model('User', UserSchema); |
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | var mongoose = require('mongoose'); |
| 2 | 1 | var Schema = mongoose.Schema; |
| 3 | 1 | var ObjectId = Schema.ObjectId; |
| 4 | ||
| 5 | 1 | var TopicSchema = new Schema({ |
| 6 | title: { type: String }, | |
| 7 | content: { type: String }, | |
| 8 | author_id: { type: ObjectId }, | |
| 9 | top: { type: Boolean, default: false }, | |
| 10 | reply_count: { type: Number, default: 0 }, | |
| 11 | visit_count: { type: Number, default: 0 }, | |
| 12 | collect_count: { type: Number, default: 0 }, | |
| 13 | create_at: { type: Date, default: Date.now }, | |
| 14 | update_at: { type: Date, default: Date.now }, | |
| 15 | last_reply: { type: ObjectId }, | |
| 16 | last_reply_at: { type: Date, default: Date.now }, | |
| 17 | content_is_html: { type: Boolean } | |
| 18 | }); | |
| 19 | ||
| 20 | 1 | mongoose.model('Topic', TopicSchema); |
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | var mongoose = require('mongoose'); |
| 2 | 1 | var Schema = mongoose.Schema; |
| 3 | 1 | var ObjectId = Schema.ObjectId; |
| 4 | ||
| 5 | 1 | var TopicTagSchema = new Schema({ |
| 6 | topic_id: { type: ObjectId }, | |
| 7 | tag_id: { type: ObjectId }, | |
| 8 | create_at: { type: Date, default: Date.now } | |
| 9 | }); | |
| 10 | ||
| 11 | 1 | mongoose.model('TopicTag', TopicTagSchema); |
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | var mongoose = require('mongoose'); |
| 2 | 1 | var Schema = mongoose.Schema; |
| 3 | 1 | var ObjectId = Schema.ObjectId; |
| 4 | ||
| 5 | 1 | var ReplySchema = new Schema({ |
| 6 | content: { type: String }, | |
| 7 | topic_id: { type: ObjectId, index: true }, | |
| 8 | author_id: { type: ObjectId }, | |
| 9 | reply_id : { type: ObjectId }, | |
| 10 | create_at: { type: Date, default: Date.now }, | |
| 11 | update_at: { type: Date, default: Date.now }, | |
| 12 | content_is_html: { type: Boolean } | |
| 13 | }); | |
| 14 | ||
| 15 | 1 | mongoose.model('Reply', ReplySchema); |
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | var mongoose = require('mongoose'); |
| 2 | 1 | var Schema = mongoose.Schema; |
| 3 | 1 | var ObjectId = Schema.ObjectId; |
| 4 | ||
| 5 | 1 | var TopicCollectSchema = new Schema({ |
| 6 | user_id: { type: ObjectId }, | |
| 7 | topic_id: { type: ObjectId }, | |
| 8 | create_at: { type: Date, default: Date.now } | |
| 9 | }); | |
| 10 | ||
| 11 | 1 | mongoose.model('TopicCollect', TopicCollectSchema); |
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | var mongoose = require('mongoose'); |
| 2 | 1 | var Schema = mongoose.Schema; |
| 3 | 1 | var ObjectId = Schema.ObjectId; |
| 4 | ||
| 5 | 1 | var TagCollectSchema = new Schema({ |
| 6 | user_id: { type: ObjectId, index: true }, | |
| 7 | tag_id: { type: ObjectId }, | |
| 8 | create_at: { type: Date, default: Date.now } | |
| 9 | }); | |
| 10 | ||
| 11 | 1 | mongoose.model('TagCollect', TagCollectSchema); |
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | var mongoose = require('mongoose'); |
| 2 | 1 | var Schema = mongoose.Schema; |
| 3 | 1 | var ObjectId = Schema.ObjectId; |
| 4 | ||
| 5 | 1 | var RelationSchema = new Schema({ |
| 6 | user_id: { type: ObjectId }, | |
| 7 | follow_id: { type: ObjectId }, | |
| 8 | create_at: { type: Date, default: Date.now } | |
| 9 | }); | |
| 10 | ||
| 11 | 1 | mongoose.model('Relation', RelationSchema); |
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | var mongoose = require('mongoose'); |
| 2 | 1 | var Schema = mongoose.Schema; |
| 3 | 1 | var ObjectId = Schema.ObjectId; |
| 4 | ||
| 5 | /* | |
| 6 | * type: | |
| 7 | * reply: xx 回复了你的话题 | |
| 8 | * reply2: xx 在话题中回复了你 | |
| 9 | * follow: xx 关注了你 | |
| 10 | * at: xx @了你 | |
| 11 | */ | |
| 12 | ||
| 13 | 1 | var MessageSchema = new Schema({ |
| 14 | type: { type: String }, | |
| 15 | master_id: { type: ObjectId, index: true }, | |
| 16 | author_id: { type: ObjectId }, | |
| 17 | topic_id: { type: ObjectId }, | |
| 18 | has_read: { type: Boolean, default: false }, | |
| 19 | create_at: { type: Date, default: Date.now } | |
| 20 | }); | |
| 21 | ||
| 22 | 1 | mongoose.model('Message', MessageSchema); |
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | var models = require('../models'), |
| 2 | Message = models.Message; | |
| 3 | ||
| 4 | 1 | var user_ctrl = require('./user'); |
| 5 | 1 | var mail_ctrl = require('./mail'); |
| 6 | 1 | var topic_ctrl = require('./topic'); |
| 7 | ||
| 8 | 1 | var EventProxy = require('eventproxy'); |
| 9 | ||
| 10 | 1 | exports.index = function(req,res,next){ |
| 11 | 0 | if(!req.session.user){ |
| 12 | 0 | res.redirect('home'); |
| 13 | 0 | return; |
| 14 | } | |
| 15 | ||
| 16 | 0 | var message_ids = []; |
| 17 | 0 | var user_id = req.session.user._id; |
| 18 | 0 | Message.find({master_id:user_id},[],{sort:[['create_at','desc']]},function(err,docs){ |
| 19 | 0 | if(err) return next(err); |
| 20 | 0 | for(var i=0; i<docs.length; i++){ |
| 21 | 0 | message_ids.push(docs[i]._id); |
| 22 | } | |
| 23 | 0 | var messages = []; |
| 24 | 0 | if(message_ids.length == 0){ |
| 25 | 0 | res.render('message/index',{has_read_messages:[],hasnot_read_messages:[]}); |
| 26 | 0 | return; |
| 27 | } | |
| 28 | 0 | var proxy = EventProxy.create(); |
| 29 | 0 | var render = function(){ |
| 30 | 0 | var has_read_messages = []; |
| 31 | 0 | var hasnot_read_messages = []; |
| 32 | 0 | for(var i=0; i<messages.length; i++){ |
| 33 | 0 | if(messages[i].is_invalid){ |
| 34 | 0 | messages[i].remove(); |
| 35 | }else{ | |
| 36 | 0 | if(messages[i].has_read){ |
| 37 | 0 | has_read_messages.push(messages[i]); |
| 38 | }else{ | |
| 39 | 0 | hasnot_read_messages.push(messages[i]); |
| 40 | } | |
| 41 | } | |
| 42 | } | |
| 43 | 0 | res.render('message/index',{has_read_messages:has_read_messages,hasnot_read_messages:hasnot_read_messages}); |
| 44 | 0 | return; |
| 45 | }; | |
| 46 | 0 | proxy.after('message_ready',message_ids.length,render); |
| 47 | 0 | for(var i=0; i<message_ids.length; i++){ |
| 48 | 0 | (function(i){ |
| 49 | 0 | get_message_by_id(message_ids[i],function(err,message){ |
| 50 | 0 | if(err) return next(err); |
| 51 | 0 | messages[i] = message; |
| 52 | 0 | proxy.trigger('message_ready'); |
| 53 | }); | |
| 54 | })(i); | |
| 55 | } | |
| 56 | }); | |
| 57 | }; | |
| 58 | ||
| 59 | 1 | exports.mark_read = function(req,res,next){ |
| 60 | 0 | if(!req.session || !req.session.user){ |
| 61 | 0 | res.send('forbidden!'); |
| 62 | 0 | return; |
| 63 | } | |
| 64 | ||
| 65 | 0 | var message_id = req.body.message_id; |
| 66 | 0 | Message.findOne({_id:message_id},function(err,message){ |
| 67 | 0 | if(err) return next(err); |
| 68 | 0 | if(!message){ |
| 69 | 0 | res.json({status:'failed'}); |
| 70 | 0 | return; |
| 71 | } | |
| 72 | 0 | if(message.master_id.toString() != req.session.user._id.toString()){ |
| 73 | 0 | res.json({status:'failed'}); |
| 74 | 0 | return; |
| 75 | } | |
| 76 | 0 | message.has_read = true; |
| 77 | 0 | message.save(function(err){ |
| 78 | 0 | if(err) return next(err); |
| 79 | 0 | res.json({status:'success'}); |
| 80 | }); | |
| 81 | }); | |
| 82 | }; | |
| 83 | ||
| 84 | 1 | exports.mark_all_read = function(req,res,next){ |
| 85 | 0 | if(!req.session || !req.session.user){ |
| 86 | 0 | res.send('forbidden!'); |
| 87 | 0 | return; |
| 88 | } | |
| 89 | ||
| 90 | 0 | Message.find({master_id:req.session.user._id,has_read:false},function(err,messages){ |
| 91 | 0 | if(messages.length == 0){ |
| 92 | 0 | res.json({'status':'success'}); |
| 93 | 0 | return; |
| 94 | } | |
| 95 | 0 | var proxy = EventProxy.create(); |
| 96 | 0 | var done = function(){ |
| 97 | 0 | res.json({'status':'success'}); |
| 98 | } | |
| 99 | 0 | proxy.after('marked',messages.length,done); |
| 100 | 0 | for(var i=0; i<messages.length; i++){ |
| 101 | 0 | var message = messages[i]; |
| 102 | 0 | message.has_read = true; |
| 103 | 0 | message.save(function(err){ |
| 104 | 0 | proxy.trigger('marked'); |
| 105 | }); | |
| 106 | } | |
| 107 | }); | |
| 108 | }; | |
| 109 | ||
| 110 | 1 | function send_reply_message(master_id,author_id,topic_id){ |
| 111 | 0 | var message = new Message(); |
| 112 | 0 | message.type = 'reply'; |
| 113 | 0 | message.master_id = master_id; |
| 114 | 0 | message.author_id = author_id; |
| 115 | 0 | message.topic_id = topic_id; |
| 116 | 0 | message.save(function(err){ |
| 117 | 0 | user_ctrl.get_user_by_id(master_id,function(err,master){ |
| 118 | 0 | if(master && master.receive_reply_mail){ |
| 119 | 0 | message.has_read = true; |
| 120 | 0 | message.save(); |
| 121 | 0 | get_message_by_id(message._id,function(err,msg){ |
| 122 | 0 | mail_ctrl.send_reply_mail(master.email,msg); |
| 123 | }); | |
| 124 | } | |
| 125 | }); | |
| 126 | }); | |
| 127 | } | |
| 128 | ||
| 129 | 1 | function send_reply2_message(master_id,author_id,topic_id){ |
| 130 | 0 | var message = new Message(); |
| 131 | 0 | message.type = 'reply2'; |
| 132 | 0 | message.master_id = master_id; |
| 133 | 0 | message.author_id = author_id; |
| 134 | 0 | message.topic_id = topic_id; |
| 135 | 0 | message.save(function(err){ |
| 136 | 0 | user_ctrl.get_user_by_id(master_id,function(err,master){ |
| 137 | 0 | if(master && master.receive_reply_mail){ |
| 138 | 0 | message.has_read = true; |
| 139 | 0 | message.save(); |
| 140 | 0 | get_message_by_id(message._id,function(err,msg){ |
| 141 | 0 | mail_ctrl.send_reply_mail(master.email,msg); |
| 142 | }); | |
| 143 | } | |
| 144 | }); | |
| 145 | }); | |
| 146 | } | |
| 147 | ||
| 148 | 1 | function send_at_message(master_id, author_id, topic_id, callback) { |
| 149 | 0 | var message = new Message(); |
| 150 | 0 | message.type = 'at'; |
| 151 | 0 | message.master_id = master_id; |
| 152 | 0 | message.author_id = author_id; |
| 153 | 0 | message.topic_id = topic_id; |
| 154 | 0 | message.save(function (err) { |
| 155 | 0 | user_ctrl.get_user_by_id(master_id, function (err, master) { |
| 156 | 0 | if (master && master.receive_at_mail) { |
| 157 | 0 | message.has_read = true; |
| 158 | 0 | message.save(); |
| 159 | 0 | get_message_by_id(message._id, function (err, msg) { |
| 160 | 0 | mail_ctrl.send_at_mail(master.email,msg); |
| 161 | }); | |
| 162 | } | |
| 163 | }); | |
| 164 | 0 | callback(err); |
| 165 | }); | |
| 166 | } | |
| 167 | ||
| 168 | 1 | function send_follow_message(follow_id,author_id){ |
| 169 | 0 | var message = new Message(); |
| 170 | 0 | message.type = 'follow'; |
| 171 | 0 | message.master_id = follow_id; |
| 172 | 0 | message.author_id = author_id; |
| 173 | 0 | message.save(); |
| 174 | } | |
| 175 | ||
| 176 | 1 | function get_message_by_id(id,cb){ |
| 177 | 0 | Message.findOne({_id:id},function(err,message){ |
| 178 | 0 | if(err) return cb(err); |
| 179 | 0 | if(message.type == 'reply' || message.type == 'reply2' || message.type == 'at'){ |
| 180 | 0 | var proxy = EventProxy.create(); |
| 181 | 0 | var done = function(author,topic){ |
| 182 | 0 | message.author = author; |
| 183 | 0 | message.topic = topic; |
| 184 | 0 | if( !author || !topic){ |
| 185 | 0 | message.is_invalid =true; |
| 186 | } | |
| 187 | 0 | return cb(err,message); |
| 188 | } | |
| 189 | 0 | proxy.assign('author_found','topic_found',done); |
| 190 | 0 | user_ctrl.get_user_by_id(message.author_id,function(err,author){ |
| 191 | 0 | if(err) return cb(err); |
| 192 | 0 | proxy.trigger('author_found',author); |
| 193 | }); | |
| 194 | 0 | topic_ctrl.get_topic_by_id(message.topic_id,function(err,topic,tags,author){ |
| 195 | 0 | if(err) return cb(err); |
| 196 | 0 | proxy.trigger('topic_found',topic); |
| 197 | }); | |
| 198 | } | |
| 199 | 0 | if(message.type == 'follow'){ |
| 200 | 0 | user_ctrl.get_user_by_id(message.author_id,function(err,author){ |
| 201 | 0 | if(err) return cb(err); |
| 202 | 0 | message.author = author; |
| 203 | 0 | if(!author){ |
| 204 | 0 | message.is_invalid =true; |
| 205 | } | |
| 206 | 0 | return cb(err,message); |
| 207 | }); | |
| 208 | } | |
| 209 | }); | |
| 210 | } | |
| 211 | ||
| 212 | 1 | function get_messages_count(master_id,cb){ |
| 213 | 0 | Message.count({master_id:master_id,has_read:false},function(err,messages_count){ |
| 214 | 0 | if(err) return cb(err); |
| 215 | 0 | return cb(err,messages_count); |
| 216 | }); | |
| 217 | 1 | }; |
| 218 | 1 | exports.get_messages_count = get_messages_count; |
| 219 | 1 | exports.send_reply_message = send_reply_message; |
| 220 | 1 | exports.send_reply2_message = send_reply2_message; |
| 221 | 1 | exports.send_follow_message = send_follow_message; |
| 222 | 1 | exports.send_at_message = send_at_message; |
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | var models = require('../models'); |
| 2 | 1 | var User = models.User; |
| 3 | 1 | var Reply = models.Reply; |
| 4 | 1 | var Relation = models.Relation; |
| 5 | 1 | var Message = models.Message; |
| 6 | 1 | var TagCollect = models.TagCollect; |
| 7 | 1 | var TopicCollect = models.TopicCollect; |
| 8 | 1 | var tag_ctrl = require('./tag'); |
| 9 | 1 | var topic_ctrl = require('./topic'); |
| 10 | 1 | var message_ctrl = require('./message'); |
| 11 | 1 | var Util = require('../libs/util'); |
| 12 | 1 | var config = require('../conf'); |
| 13 | 1 | var EventProxy = require('eventproxy'); |
| 14 | 1 | var check = require('validator').check; |
| 15 | 1 | var sanitize = require('validator').sanitize; |
| 16 | 1 | var crypto = require('crypto'); |
| 17 | ||
| 18 | 1 | exports.index = function (req, res, next) { |
| 19 | 0 | var user_name = req.params.name; |
| 20 | 0 | get_user_by_name(user_name, function (err, user) { |
| 21 | 0 | if (!user) { |
| 22 | 0 | res.render('notify/notify', {error: '这个用户不存在。'}); |
| 23 | 0 | return; |
| 24 | } | |
| 25 | ||
| 26 | 0 | var render = function (recent_topics, recent_replies, relation) { |
| 27 | 0 | user.friendly_create_at = Util.format_date(user.create_at, true); |
| 28 | 0 | res.render('user/index', { |
| 29 | user: user, | |
| 30 | recent_topics: recent_topics, | |
| 31 | recent_replies: recent_replies, | |
| 32 | relation: relation | |
| 33 | }); | |
| 34 | }; | |
| 35 | ||
| 36 | 0 | var proxy = EventProxy.create(); |
| 37 | 0 | proxy.assign('recent_topics', 'recent_replies', 'relation', render); |
| 38 | ||
| 39 | 0 | var query = {author_id: user._id}; |
| 40 | 0 | var opt = {limit: 5, sort: [['create_at', 'desc']]}; |
| 41 | 0 | topic_ctrl.get_topics_by_query(query, opt, function (err, recent_topics) { |
| 42 | 0 | if (err) { |
| 43 | 0 | return next(err); |
| 44 | } | |
| 45 | 0 | proxy.trigger('recent_topics', recent_topics); |
| 46 | }); | |
| 47 | ||
| 48 | 0 | Reply.find({author_id: user._id}, function (err, replies) { |
| 49 | 0 | if (err) { |
| 50 | 0 | return next(err); |
| 51 | } | |
| 52 | 0 | var topic_ids = []; |
| 53 | 0 | for (var i = 0; i < replies.length; i++) { |
| 54 | 0 | if (topic_ids.indexOf(replies[i].topic_id.toString()) < 0) { |
| 55 | 0 | topic_ids.push(replies[i].topic_id.toString()); |
| 56 | } | |
| 57 | } | |
| 58 | 0 | var query = {_id: {'$in': topic_ids}}; |
| 59 | 0 | var opt = {limit: 5, sort: [['create_at', 'desc']]}; |
| 60 | 0 | topic_ctrl.get_topics_by_query(query, opt, function (err, topics) { |
| 61 | 0 | if (err) { |
| 62 | 0 | return next(err); |
| 63 | } | |
| 64 | 0 | proxy.trigger('recent_replies', topics); |
| 65 | }); | |
| 66 | }); | |
| 67 | ||
| 68 | 0 | if (!req.session.user) { |
| 69 | 0 | proxy.trigger('relation', null); |
| 70 | } else { | |
| 71 | 0 | Relation.findOne({user_id: req.session.user._id, follow_id: user._id}, function (err, doc) { |
| 72 | 0 | if (err) { |
| 73 | 0 | return next(err); |
| 74 | } | |
| 75 | 0 | proxy.trigger('relation', doc); |
| 76 | }); | |
| 77 | } | |
| 78 | }); | |
| 79 | }; | |
| 80 | ||
| 81 | 1 | exports.show_stars = function (req, res, next) { |
| 82 | 0 | get_users_by_query({is_star: true}, {}, function (err, stars) { |
| 83 | 0 | if (err) { |
| 84 | 0 | return next(err); |
| 85 | } | |
| 86 | 0 | res.render('user/stars', {stars: stars}); |
| 87 | }); | |
| 88 | }; | |
| 89 | ||
| 90 | 1 | exports.setting = function (req, res, next) { |
| 91 | 0 | if (!req.session.user) { |
| 92 | 0 | res.redirect('home'); |
| 93 | 0 | return; |
| 94 | } | |
| 95 | 0 | var method = req.method.toLowerCase(); |
| 96 | 0 | if (method !== 'post') { |
| 97 | 0 | get_user_by_id(req.session.user._id, function (err, user) { |
| 98 | 0 | if (err) { |
| 99 | 0 | return next(err); |
| 100 | } | |
| 101 | 0 | if (req.query.save === 'success') { |
| 102 | 0 | user.success = '保存成功。'; |
| 103 | } | |
| 104 | 0 | user.error = null; |
| 105 | 0 | return res.render('user/setting', user); |
| 106 | }); | |
| 107 | 0 | return; |
| 108 | } | |
| 109 | // post | |
| 110 | 0 | var action = req.body.action; |
| 111 | 0 | if (action === 'change_setting') { |
| 112 | 0 | var name = sanitize(req.body.name).trim(); |
| 113 | 0 | name = sanitize(name).xss(); |
| 114 | 0 | var email = sanitize(req.body.email).trim(); |
| 115 | 0 | email = sanitize(email).xss(); |
| 116 | 0 | var url = sanitize(req.body.url).trim(); |
| 117 | 0 | url = sanitize(url).xss(); |
| 118 | 0 | var profile_image_url = sanitize(sanitize(req.body.profile_image_url).trim()).xss(); |
| 119 | 0 | var location = sanitize(req.body.location).trim(); |
| 120 | 0 | location = sanitize(location).xss(); |
| 121 | 0 | var signature = sanitize(req.body.signature).trim(); |
| 122 | 0 | signature = sanitize(signature).xss(); |
| 123 | 0 | var profile = sanitize(req.body.profile).trim(); |
| 124 | 0 | profile = sanitize(profile).xss(); |
| 125 | 0 | var weibo = sanitize(req.body.weibo).trim(); |
| 126 | 0 | weibo = sanitize(weibo).xss(); |
| 127 | 0 | var receive_at_mail = req.body.receive_at_mail === 'on' ? true: false; |
| 128 | 0 | var receive_reply_mail = req.body.receive_reply_mail === 'on' ? true: false; |
| 129 | ||
| 130 | 0 | if (url !== '') { |
| 131 | 0 | try { |
| 132 | 0 | if (url.indexOf('http://') < 0) { |
| 133 | 0 | url = 'http://' + url; |
| 134 | } | |
| 135 | 0 | check(url, '不正确的个人网站。').isUrl(); |
| 136 | } catch (e) { | |
| 137 | 0 | res.render('user/setting', { |
| 138 | error: e.message, | |
| 139 | name: name, | |
| 140 | email: email, | |
| 141 | url: url, | |
| 142 | profile_image_url: profile_image_url, | |
| 143 | location: location, | |
| 144 | signature: signature, | |
| 145 | profile: profile, | |
| 146 | weibo: weibo, | |
| 147 | receive_at_mail: receive_at_mail, | |
| 148 | receive_reply_mail: receive_reply_mail | |
| 149 | }); | |
| 150 | 0 | return; |
| 151 | } | |
| 152 | } | |
| 153 | 0 | if (weibo) { |
| 154 | 0 | try { |
| 155 | 0 | if (weibo.indexOf('http://') < 0) { |
| 156 | 0 | weibo = 'http://' + weibo; |
| 157 | } | |
| 158 | 0 | check(weibo, '不正确的微博地址。').isUrl(); |
| 159 | } catch (e) { | |
| 160 | 0 | res.render('user/setting', { |
| 161 | error: e.message, | |
| 162 | name: name, | |
| 163 | email: email, | |
| 164 | url: url, | |
| 165 | profile_image_url: profile_image_url, | |
| 166 | location: location, | |
| 167 | signature: signature, | |
| 168 | profile: profile, | |
| 169 | weibo: weibo, | |
| 170 | receive_at_mail: receive_at_mail, | |
| 171 | receive_reply_mail: receive_reply_mail | |
| 172 | }); | |
| 173 | 0 | return; |
| 174 | } | |
| 175 | } | |
| 176 | ||
| 177 | 0 | get_user_by_id(req.session.user._id, function (err, user) { |
| 178 | 0 | if (err) { |
| 179 | 0 | return next(err); |
| 180 | } | |
| 181 | 0 | user.url = url; |
| 182 | 0 | user.profile_image_url = profile_image_url; |
| 183 | 0 | user.location = location; |
| 184 | 0 | user.signature = signature; |
| 185 | 0 | user.profile = profile; |
| 186 | 0 | user.weibo = weibo; |
| 187 | 0 | user.receive_at_mail = receive_at_mail; |
| 188 | 0 | user.receive_reply_mail = receive_reply_mail; |
| 189 | 0 | user.save(function (err) { |
| 190 | 0 | if (err) { |
| 191 | 0 | return next(err); |
| 192 | } | |
| 193 | 0 | return res.redirect('/setting?save=success'); |
| 194 | }); | |
| 195 | }); | |
| 196 | ||
| 197 | } | |
| 198 | 0 | if (action === 'change_password') { |
| 199 | 0 | var old_pass = sanitize(req.body.old_pass).trim(); |
| 200 | 0 | var new_pass = sanitize(req.body.new_pass).trim(); |
| 201 | ||
| 202 | 0 | get_user_by_id(req.session.user._id, function (err, user) { |
| 203 | 0 | if (err) { |
| 204 | 0 | return next(err); |
| 205 | } | |
| 206 | 0 | var md5sum = crypto.createHash('md5'); |
| 207 | 0 | md5sum.update(old_pass); |
| 208 | 0 | old_pass = md5sum.digest('hex'); |
| 209 | ||
| 210 | 0 | if (old_pass !== user.pass) { |
| 211 | 0 | res.render('user/setting', { |
| 212 | error: '当前密码不正确。', | |
| 213 | name: user.name, | |
| 214 | email: user.email, | |
| 215 | url: user.url, | |
| 216 | profile_image_url: user.profile_image_url, | |
| 217 | location: user.location, | |
| 218 | signature: user.signature, | |
| 219 | profile: user.profile, | |
| 220 | weibo: user.weibo, | |
| 221 | receive_at_mail: user.receive_at_mail, | |
| 222 | receive_reply_mail: user.receive_reply_mail | |
| 223 | }); | |
| 224 | 0 | return; |
| 225 | } | |
| 226 | ||
| 227 | 0 | md5sum = crypto.createHash('md5'); |
| 228 | 0 | md5sum.update(new_pass); |
| 229 | 0 | new_pass = md5sum.digest('hex'); |
| 230 | ||
| 231 | 0 | user.pass = new_pass; |
| 232 | 0 | user.save(function (err) { |
| 233 | 0 | if (err) { |
| 234 | 0 | return next(err); |
| 235 | } | |
| 236 | 0 | res.render('user/setting', { |
| 237 | success: '密码已被修改。', | |
| 238 | name: user.name, | |
| 239 | email: user.email, | |
| 240 | url: user.url, | |
| 241 | profile_image_url: user.profile_image_url, | |
| 242 | location: user.location, | |
| 243 | signature: user.signature, | |
| 244 | profile: user.profile, | |
| 245 | weibo: user.weibo, | |
| 246 | receive_at_mail: user.receive_at_mail, | |
| 247 | receive_reply_mail: user.receive_reply_mail | |
| 248 | }); | |
| 249 | 0 | return; |
| 250 | ||
| 251 | }); | |
| 252 | }); | |
| 253 | } | |
| 254 | }; | |
| 255 | ||
| 256 | 1 | exports.follow = function (req, res, next) { |
| 257 | 0 | if (!req.session || !req.session.user) { |
| 258 | 0 | res.send('forbidden!'); |
| 259 | 0 | return; |
| 260 | } | |
| 261 | 0 | var follow_id = req.body.follow_id; |
| 262 | 0 | get_user_by_id(follow_id, function (err, user) { |
| 263 | 0 | if (err) { |
| 264 | 0 | return next(err); |
| 265 | } | |
| 266 | 0 | if (!user) { |
| 267 | 0 | res.json({status: 'failed'}); |
| 268 | } | |
| 269 | ||
| 270 | 0 | var proxy = EventProxy.create(); |
| 271 | 0 | var done = function () { |
| 272 | 0 | res.json({ status: 'success' }); |
| 273 | }; | |
| 274 | 0 | proxy.assign('relation_saved', 'message_saved', done); |
| 275 | 0 | Relation.findOne({user_id: req.session.user._id, follow_id: user._id}, function (err, doc) { |
| 276 | 0 | if (err) { |
| 277 | 0 | return next(err); |
| 278 | } | |
| 279 | 0 | if (doc) { |
| 280 | 0 | res.json({ status: 'success' }); |
| 281 | 0 | return; |
| 282 | } | |
| 283 | ||
| 284 | 0 | var relation = new Relation(); |
| 285 | 0 | relation.user_id = req.session.user._id; |
| 286 | 0 | relation.follow_id = user._id; |
| 287 | 0 | relation.save(); |
| 288 | 0 | proxy.trigger('relation_saved'); |
| 289 | ||
| 290 | 0 | get_user_by_id(req.session.user._id, function (err, me) { |
| 291 | 0 | if (err) { |
| 292 | 0 | return next(err); |
| 293 | } | |
| 294 | 0 | me.following_count += 1; |
| 295 | 0 | me.save(); |
| 296 | }); | |
| 297 | ||
| 298 | 0 | user.follower_count += 1; |
| 299 | 0 | user.save(); |
| 300 | ||
| 301 | 0 | req.session.user.following_count += 1; |
| 302 | }); | |
| 303 | ||
| 304 | 0 | message_ctrl.send_follow_message(follow_id, req.session.user._id); |
| 305 | 0 | proxy.trigger('message_saved'); |
| 306 | }); | |
| 307 | }; | |
| 308 | ||
| 309 | 1 | exports.un_follow = function (req, res, next) { |
| 310 | 0 | if (!req.session || !req.session.user) { |
| 311 | 0 | res.send('forbidden!'); |
| 312 | 0 | return; |
| 313 | } | |
| 314 | 0 | var follow_id = req.body.follow_id; |
| 315 | 0 | get_user_by_id(follow_id, function (err, user) { |
| 316 | 0 | if (err) { |
| 317 | 0 | return next(err); |
| 318 | } | |
| 319 | 0 | if (!user) { |
| 320 | 0 | res.json({status: 'failed'}); |
| 321 | 0 | return; |
| 322 | } | |
| 323 | 0 | Relation.remove({user_id: req.session.user._id, follow_id: user._id}, function (err) { |
| 324 | 0 | if (err) { |
| 325 | 0 | return next(err); |
| 326 | } | |
| 327 | 0 | res.json({status: 'success'}); |
| 328 | }); | |
| 329 | ||
| 330 | 0 | get_user_by_id(req.session.user._id, function (err, me) { |
| 331 | 0 | if (err) { |
| 332 | 0 | return next(err); |
| 333 | } | |
| 334 | 0 | me.following_count -= 1; |
| 335 | 0 | me.save(); |
| 336 | }); | |
| 337 | ||
| 338 | 0 | user.follower_count -= 1; |
| 339 | 0 | user.save(); |
| 340 | ||
| 341 | 0 | req.session.user.following_count -= 1; |
| 342 | }); | |
| 343 | }; | |
| 344 | ||
| 345 | 1 | exports.toggle_star = function (req, res, next) { |
| 346 | 0 | if (!req.session.user || !req.session.user.is_admin) { |
| 347 | 0 | res.send('forbidden!</strong>'); |
| 348 | 0 | return; |
| 349 | } | |
| 350 | 0 | var user_id = req.body.user_id; |
| 351 | 0 | get_user_by_id(user_id, function (err, user) { |
| 352 | 0 | if (err) { |
| 353 | 0 | return next(err); |
| 354 | } | |
| 355 | 0 | user.is_star = !!user.is_star; |
| 356 | 0 | user.save(function (err) { |
| 357 | 0 | if (err) { |
| 358 | 0 | return next(err); |
| 359 | } | |
| 360 | 0 | res.json({ status: 'success' }); |
| 361 | }); | |
| 362 | }); | |
| 363 | }; | |
| 364 | ||
| 365 | 1 | exports.get_collect_tags = function (req, res, next) { |
| 366 | 0 | if (!req.session.user) { |
| 367 | 0 | res.redirect('home'); |
| 368 | 0 | return; |
| 369 | } | |
| 370 | 0 | TagCollect.find({ user_id: req.session.user._id }, function (err, docs) { |
| 371 | 0 | if (err) { |
| 372 | 0 | return next(err); |
| 373 | } | |
| 374 | 0 | var ids = []; |
| 375 | 0 | for (var i = 0; i < docs.length; i++) { |
| 376 | 0 | ids.push(docs[i].tag_id); |
| 377 | } | |
| 378 | 0 | tag_ctrl.get_tags_by_ids(ids, function (err, tags) { |
| 379 | 0 | if (err) { |
| 380 | 0 | return next(err); |
| 381 | } | |
| 382 | 0 | res.render('user/collect_tags', { tags: tags }); |
| 383 | }); | |
| 384 | }); | |
| 385 | }; | |
| 386 | ||
| 387 | 1 | exports.get_collect_topics = function (req, res, next) { |
| 388 | 0 | if (!req.session.user) { |
| 389 | 0 | res.redirect('home'); |
| 390 | 0 | return; |
| 391 | } | |
| 392 | ||
| 393 | 0 | var page = Number(req.query.page) || 1; |
| 394 | 0 | var limit = config.list_topic_count; |
| 395 | ||
| 396 | 0 | var render = function (topics, pages) { |
| 397 | 0 | res.render('user/collect_topics', { |
| 398 | topics: topics, | |
| 399 | current_page: page, | |
| 400 | pages: pages | |
| 401 | }); | |
| 402 | }; | |
| 403 | ||
| 404 | 0 | var proxy = EventProxy.create(); |
| 405 | 0 | proxy.assign('topics', 'pages', render); |
| 406 | ||
| 407 | 0 | TopicCollect.find({ user_id: req.session.user._id }, function (err, docs) { |
| 408 | 0 | if (err) { |
| 409 | 0 | return next(err); |
| 410 | } | |
| 411 | 0 | var ids = []; |
| 412 | 0 | for (var i = 0; i < docs.length; i++) { |
| 413 | 0 | ids.push(docs[i].topic_id); |
| 414 | } | |
| 415 | 0 | var query = { _id: { '$in': ids } }; |
| 416 | 0 | var opt = { |
| 417 | skip: (page - 1) * limit, | |
| 418 | limit: limit, | |
| 419 | sort: [ [ 'create_at', 'desc' ] ] | |
| 420 | }; | |
| 421 | 0 | topic_ctrl.get_topics_by_query(query, opt, function (err, topics) { |
| 422 | 0 | if (err) { |
| 423 | 0 | return next(err); |
| 424 | } | |
| 425 | 0 | proxy.trigger('topics', topics); |
| 426 | }); | |
| 427 | 0 | topic_ctrl.get_count_by_query(query, function (err, all_topics_count) { |
| 428 | 0 | if (err) { |
| 429 | 0 | return next(err); |
| 430 | } | |
| 431 | 0 | var pages = Math.ceil(all_topics_count / limit); |
| 432 | 0 | proxy.trigger('pages', pages); |
| 433 | }); | |
| 434 | }); | |
| 435 | }; | |
| 436 | ||
| 437 | 1 | exports.get_followings = function (req, res, next) { |
| 438 | 0 | if (!req.session.user) { |
| 439 | 0 | res.redirect('home'); |
| 440 | 0 | return; |
| 441 | } | |
| 442 | 0 | Relation.find({user_id: req.session.user._id}, function (err, docs) { |
| 443 | 0 | if (err) { |
| 444 | 0 | return next(err); |
| 445 | } | |
| 446 | 0 | var ids = []; |
| 447 | 0 | for (var i = 0; i < docs.length; i++) { |
| 448 | 0 | ids.push(docs[i].follow_id); |
| 449 | } | |
| 450 | 0 | get_users_by_ids(ids, function (err, users) { |
| 451 | 0 | if (err) { |
| 452 | 0 | return next(err); |
| 453 | } | |
| 454 | 0 | res.render('user/followings', {users: users}); |
| 455 | }); | |
| 456 | }); | |
| 457 | }; | |
| 458 | ||
| 459 | 1 | exports.get_followers = function (req, res, next) { |
| 460 | 0 | if (!req.session.user) { |
| 461 | 0 | res.redirect('home'); |
| 462 | 0 | return; |
| 463 | } | |
| 464 | 0 | Relation.find({follow_id: req.session.user._id}, function (err, docs) { |
| 465 | 0 | if (err) { |
| 466 | 0 | return next(err); |
| 467 | } | |
| 468 | 0 | var ids = []; |
| 469 | 0 | for (var i = 0; i < docs.length; i++) { |
| 470 | 0 | ids.push(docs[i].user_id); |
| 471 | } | |
| 472 | 0 | get_users_by_ids(ids, function (err, users) { |
| 473 | 0 | if (err) { |
| 474 | 0 | return next(err); |
| 475 | } | |
| 476 | 0 | res.render('user/followers', {users: users}); |
| 477 | }); | |
| 478 | }); | |
| 479 | }; | |
| 480 | ||
| 481 | 1 | exports.top100 = function (req, res, next) { |
| 482 | 0 | var opt = {limit: 100, sort: [['score', 'desc']]}; |
| 483 | 0 | get_users_by_query({}, opt, function (err, tops) { |
| 484 | 0 | if (err) { |
| 485 | 0 | return next(err); |
| 486 | } | |
| 487 | 0 | res.render('user/top100', {users: tops}); |
| 488 | }); | |
| 489 | }; | |
| 490 | ||
| 491 | 1 | exports.list_topics = function (req, res, next) { |
| 492 | 0 | var user_name = req.params.name; |
| 493 | 0 | var page = Number(req.query.page) || 1; |
| 494 | 0 | var limit = config.list_topic_count; |
| 495 | ||
| 496 | 0 | get_user_by_name(user_name, function (err, user) { |
| 497 | 0 | if (!user) { |
| 498 | 0 | res.render('notify/notify', {error: '这个用户不存在。'}); |
| 499 | 0 | return; |
| 500 | } | |
| 501 | ||
| 502 | 0 | var render = function (topics, relation, pages) { |
| 503 | 0 | user.friendly_create_at = Util.format_date(user.create_at, true); |
| 504 | 0 | res.render('user/topics', { |
| 505 | user: user, | |
| 506 | topics: topics, | |
| 507 | relation: relation, | |
| 508 | current_page: page, | |
| 509 | pages: pages | |
| 510 | }); | |
| 511 | }; | |
| 512 | ||
| 513 | 0 | var proxy = EventProxy.create(); |
| 514 | 0 | proxy.assign('topics', 'relation', 'pages', render); |
| 515 | ||
| 516 | 0 | var query = {'author_id': user._id}; |
| 517 | 0 | var opt = {skip: (page - 1) * limit, limit: limit, sort: [['create_at', 'desc']]}; |
| 518 | 0 | topic_ctrl.get_topics_by_query(query, opt, function (err, topics) { |
| 519 | 0 | if (err) { |
| 520 | 0 | return next(err); |
| 521 | } | |
| 522 | 0 | proxy.trigger('topics', topics); |
| 523 | }); | |
| 524 | ||
| 525 | 0 | if (!req.session.user) { |
| 526 | 0 | proxy.trigger('relation', null); |
| 527 | } else { | |
| 528 | 0 | Relation.findOne({user_id: req.session.user._id, follow_id: user._id}, function (err, doc) { |
| 529 | 0 | if (err) { |
| 530 | 0 | return next(err); |
| 531 | } | |
| 532 | 0 | proxy.trigger('relation', doc); |
| 533 | }); | |
| 534 | } | |
| 535 | ||
| 536 | 0 | topic_ctrl.get_count_by_query(query, function (err, all_topics_count) { |
| 537 | 0 | if (err) { |
| 538 | 0 | return next(err); |
| 539 | } | |
| 540 | 0 | var pages = Math.ceil(all_topics_count / limit); |
| 541 | 0 | proxy.trigger('pages', pages); |
| 542 | }); | |
| 543 | }); | |
| 544 | }; | |
| 545 | ||
| 546 | 1 | exports.list_replies = function (req, res, next) { |
| 547 | 0 | var user_name = req.params.name; |
| 548 | 0 | var page = Number(req.query.page) || 1; |
| 549 | 0 | var limit = config.list_topic_count; |
| 550 | ||
| 551 | 0 | get_user_by_name(user_name, function (err, user) { |
| 552 | 0 | if (!user) { |
| 553 | 0 | res.render('notify/notify', {error: '这个用户不存在。'}); |
| 554 | 0 | return; |
| 555 | } | |
| 556 | ||
| 557 | 0 | var render = function (topics, relation, pages) { |
| 558 | 0 | user.friendly_create_at = Util.format_date(user.create_at, true); |
| 559 | 0 | res.render('user/replies', { |
| 560 | user: user, | |
| 561 | topics: topics, | |
| 562 | relation: relation, | |
| 563 | current_page: page, | |
| 564 | pages: pages | |
| 565 | }); | |
| 566 | }; | |
| 567 | ||
| 568 | 0 | var proxy = EventProxy.create(); |
| 569 | 0 | proxy.assign('topics', 'relation', 'pages', render); |
| 570 | ||
| 571 | 0 | Reply.find({author_id: user._id}, function (err, replies) { |
| 572 | 0 | if (err) { |
| 573 | 0 | return next(err); |
| 574 | } | |
| 575 | 0 | var topic_ids = []; |
| 576 | 0 | for (var i = 0; i < replies.length; i++) { |
| 577 | 0 | if (topic_ids.indexOf(replies[i].topic_id.toString()) < 0) { |
| 578 | 0 | topic_ids.push(replies[i].topic_id); |
| 579 | } | |
| 580 | } | |
| 581 | 0 | var query = {'_id': {'$in': topic_ids}}; |
| 582 | 0 | var opt = {skip: (page - 1) * limit, limit: limit, sort: [['create_at', 'desc']]}; |
| 583 | 0 | topic_ctrl.get_topics_by_query(query, opt, function (err, topics) { |
| 584 | 0 | if (err) { |
| 585 | 0 | return next(err); |
| 586 | } | |
| 587 | 0 | proxy.trigger('topics', topics); |
| 588 | }); | |
| 589 | ||
| 590 | 0 | topic_ctrl.get_count_by_query(query, function (err, all_topics_count) { |
| 591 | 0 | if (err) { |
| 592 | 0 | return next(err); |
| 593 | } | |
| 594 | 0 | var pages = Math.ceil(all_topics_count / limit); |
| 595 | 0 | proxy.trigger('pages', pages); |
| 596 | }); | |
| 597 | }); | |
| 598 | ||
| 599 | 0 | if (!req.session.user) { |
| 600 | 0 | proxy.trigger('relation', null); |
| 601 | } else { | |
| 602 | 0 | Relation.findOne({user_id: req.session.user._id, follow_id: user._id}, function (err, doc) { |
| 603 | 0 | if (err) { |
| 604 | 0 | return next(err); |
| 605 | } | |
| 606 | 0 | proxy.trigger('relation', doc); |
| 607 | }); | |
| 608 | } | |
| 609 | }); | |
| 610 | }; | |
| 611 | ||
| 612 | 1 | function get_user_by_id(id, cb) { |
| 613 | 0 | User.findOne({_id: id}, cb); |
| 614 | } | |
| 615 | 1 | function get_user_by_name(name, cb) { |
| 616 | 0 | User.findOne({name: name}, cb); |
| 617 | } | |
| 618 | 1 | function get_user_by_loginname(name, cb) { |
| 619 | 0 | User.findOne({loginname: name}, cb); |
| 620 | } | |
| 621 | ||
| 622 | 1 | function get_users_by_ids(ids, cb) { |
| 623 | 0 | User.find({'_id': {'$in': ids}}, cb); |
| 624 | } | |
| 625 | 1 | function get_users_by_query(query, opt, cb) { |
| 626 | 0 | User.find(query, [], opt, cb); |
| 627 | } | |
| 628 | 1 | exports.get_user_by_id = get_user_by_id; |
| 629 | 1 | exports.get_user_by_name = get_user_by_name; |
| 630 | 1 | exports.get_user_by_loginname = get_user_by_loginname; |
| 631 | 1 | exports.get_users_by_ids = get_users_by_ids; |
| 632 | 1 | exports.get_users_by_query = get_users_by_query; |
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | var models = require('../models'), |
| 2 | Tag = models.Tag, | |
| 3 | TopicTag = models.TopicTag, | |
| 4 | TagCollect = models.TagCollect; | |
| 5 | ||
| 6 | 1 | var check = require('validator').check, |
| 7 | sanitize = require('validator').sanitize; | |
| 8 | ||
| 9 | 1 | var user_ctrl = require('./user'); |
| 10 | 1 | var topic_ctrl = require('./topic'); |
| 11 | 1 | var config = require('../conf'); |
| 12 | 1 | var EventProxy = require('eventproxy'); |
| 13 | ||
| 14 | 1 | exports.list_topic = function(req,res,next){ |
| 15 | 0 | var tag_name = req.params.name; |
| 16 | 0 | var page = Number(req.query.page) || 1; |
| 17 | 0 | var limit = config.list_topic_count; |
| 18 | ||
| 19 | 0 | Tag.findOne({name:tag_name},function(err,tag){ |
| 20 | 0 | if(err) return next(err); |
| 21 | 0 | if(tag){ |
| 22 | 0 | var done = function(topic_ids,collection,hot_topics,no_reply_topics,pages){ |
| 23 | 0 | var query = {'_id':{'$in':topic_ids}}; |
| 24 | 0 | var opt = {skip:(page-1)*limit, limit:limit, sort:[['create_at','desc']]}; |
| 25 | ||
| 26 | 0 | topic_ctrl.get_topics_by_query(query,opt,function(err,topics){ |
| 27 | 0 | for(var i=0; i<topics.length; i++){ |
| 28 | 0 | for(var j=0; j<topics[i].tags.length; j++){ |
| 29 | 0 | if(topics[i].tags[j].id == tag.id){ |
| 30 | 0 | topics[i].tags[j].highlight = true; |
| 31 | } | |
| 32 | } | |
| 33 | } | |
| 34 | ||
| 35 | 0 | if (tag.background=='') { |
| 36 | 0 | var style = null; |
| 37 | } else { | |
| 38 | 0 | var style = '#wrapper {background-image: url("'+tag.background+'")}'; |
| 39 | } | |
| 40 | ||
| 41 | 0 | res.render('tag/list_topic',{ |
| 42 | tag:tag,topics:topics, | |
| 43 | current_page:page, | |
| 44 | list_topic_count:limit, | |
| 45 | in_collection:collection, | |
| 46 | hot_topics:hot_topics, | |
| 47 | no_reply_topics:no_reply_topics, | |
| 48 | pages:pages, | |
| 49 | extra_style:style | |
| 50 | }); | |
| 51 | }); | |
| 52 | } | |
| 53 | ||
| 54 | 0 | var proxy = EventProxy.create(); |
| 55 | 0 | proxy.assign('topic_ids','collection','hot_topics','no_reply_topics','pages',done); |
| 56 | ||
| 57 | 0 | TopicTag.find({tag_id:tag._id},function(err,docs){ |
| 58 | 0 | if(err) return next(err); |
| 59 | 0 | var topic_ids = []; |
| 60 | ||
| 61 | 0 | for(var i=0; i<docs.length; i++){ |
| 62 | 0 | topic_ids.push(docs[i].topic_id); |
| 63 | } | |
| 64 | 0 | proxy.trigger('topic_ids',topic_ids); |
| 65 | ||
| 66 | 0 | topic_ctrl.get_count_by_query({'_id':{'$in':topic_ids}},function(err,all_topics_count){ |
| 67 | 0 | if(err) return next(err); |
| 68 | 0 | var pages = Math.ceil(all_topics_count/limit); |
| 69 | 0 | proxy.trigger('pages',pages); |
| 70 | }); | |
| 71 | ||
| 72 | }); | |
| 73 | ||
| 74 | 0 | if(!req.session.user){ |
| 75 | 0 | proxy.trigger('collection',null); |
| 76 | }else{ | |
| 77 | 0 | TagCollect.findOne({user_id:req.session.user._id,tag_id:tag._id},function(err,doc){ |
| 78 | 0 | if(err) return next(err); |
| 79 | 0 | proxy.trigger('collection',doc); |
| 80 | }); | |
| 81 | } | |
| 82 | ||
| 83 | 0 | var opt = {limit:5, sort:[['visit_count','desc']]}; |
| 84 | 0 | topic_ctrl.get_topics_by_query({},opt,function(err,hot_topics){ |
| 85 | 0 | if(err) return next(err); |
| 86 | 0 | proxy.trigger('hot_topics',hot_topics); |
| 87 | }); | |
| 88 | ||
| 89 | 0 | opt = {limit:5, sort:[['create_at','desc']]}; |
| 90 | 0 | topic_ctrl.get_topics_by_query({reply_count:0},opt,function(err,no_reply_topics){ |
| 91 | 0 | if(err) return next(err); |
| 92 | 0 | proxy.trigger('no_reply_topics',no_reply_topics); |
| 93 | }); | |
| 94 | }else{ | |
| 95 | 0 | res.render('notify/notify',{error:'没有这个标签。'}); |
| 96 | 0 | return; |
| 97 | } | |
| 98 | }); | |
| 99 | }; | |
| 100 | ||
| 101 | 1 | exports.edit_tags = function(req,res,next){ |
| 102 | 0 | if(!req.session.user){ |
| 103 | 0 | res.render('notify/notify',{error:'你还没有登录。'}); |
| 104 | 0 | return; |
| 105 | } | |
| 106 | 0 | if(!req.session.user.is_admin){ |
| 107 | 0 | res.render('notify/notify',{error:'管理员才能编辑标签。'}); |
| 108 | 0 | return; |
| 109 | } | |
| 110 | 0 | get_all_tags(function(err,tags){ |
| 111 | 0 | if(err) return next(err); |
| 112 | 0 | res.render('tag/edit_all',{tags:tags}); |
| 113 | 0 | return; |
| 114 | }); | |
| 115 | }; | |
| 116 | ||
| 117 | 1 | exports.add = function(req,res,next){ |
| 118 | 0 | if(!req.session || !req.session.user || !req.session.user.is_admin){ |
| 119 | 0 | res.send('fobidden!'); |
| 120 | 0 | return; |
| 121 | } | |
| 122 | ||
| 123 | 0 | var name = sanitize(req.body.name).trim(); |
| 124 | 0 | name = sanitize(name).xss(); |
| 125 | 0 | var description = sanitize(req.body.description).trim(); |
| 126 | 0 | description = sanitize(description).xss(); |
| 127 | 0 | var background = sanitize(req.body.background).trim(); |
| 128 | 0 | background = sanitize(background).xss(); |
| 129 | 0 | var order = req.body.order; |
| 130 | ||
| 131 | 0 | if(name == ''){ |
| 132 | 0 | res.render('notify/notify', {error:'信息不完整。'}); |
| 133 | 0 | return; |
| 134 | } | |
| 135 | ||
| 136 | 0 | Tag.find({'name':name},function(err,tags){ |
| 137 | 0 | if(err) return next(err); |
| 138 | 0 | if(tags.length > 0){ |
| 139 | 0 | res.render('notify/notify',{error:'这个标签已存在。'}); |
| 140 | 0 | return; |
| 141 | } | |
| 142 | ||
| 143 | 0 | var tag = new Tag(); |
| 144 | 0 | tag.name = name; |
| 145 | 0 | tag.background = background; |
| 146 | 0 | tag.order = order; |
| 147 | 0 | tag.description = description; |
| 148 | 0 | tag.save(function(err){ |
| 149 | 0 | if(err) return next(err); |
| 150 | 0 | res.redirect('/tags/edit'); |
| 151 | }); | |
| 152 | }); | |
| 153 | }; | |
| 154 | ||
| 155 | 1 | exports.edit = function(req,res,next){ |
| 156 | 0 | if(!req.session.user){ |
| 157 | 0 | res.render('notify/notify',{error:'你还没有登录。'}); |
| 158 | 0 | return; |
| 159 | } | |
| 160 | 0 | if(!req.session.user.is_admin){ |
| 161 | 0 | res.render('notify/notify',{error:'管理员才能编辑标签。'}); |
| 162 | 0 | return; |
| 163 | } | |
| 164 | 0 | var tag_name = req.params.name; |
| 165 | 0 | Tag.findOne({name:tag_name},function(err,tag){ |
| 166 | 0 | if(err) return next(err); |
| 167 | 0 | if(tag){ |
| 168 | 0 | var method = req.method.toLowerCase(); |
| 169 | 0 | if(method == 'get'){ |
| 170 | 0 | get_all_tags(function(err,tags){ |
| 171 | 0 | if(err) return next(err); |
| 172 | 0 | res.render('tag/edit',{tag:tag,tags:tags}); |
| 173 | 0 | return; |
| 174 | }); | |
| 175 | } | |
| 176 | 0 | if(method == 'post'){ |
| 177 | 0 | var name = sanitize(req.body.name).trim(); |
| 178 | 0 | name = sanitize(name).xss(); |
| 179 | 0 | var order = req.body.order; |
| 180 | 0 | var background = sanitize(req.body.background).trim(); |
| 181 | 0 | background = sanitize(background).xss(); |
| 182 | 0 | var description = sanitize(req.body.description).trim(); |
| 183 | 0 | description = sanitize(description).xss(); |
| 184 | 0 | if(name == ''){ |
| 185 | 0 | res.render('notify/notify', {error:'信息不完整。'}); |
| 186 | 0 | return; |
| 187 | } | |
| 188 | 0 | tag.name = name; |
| 189 | 0 | tag.order = order; |
| 190 | 0 | tag.background = background; |
| 191 | 0 | tag.description = description; |
| 192 | 0 | tag.save(function(err){ |
| 193 | 0 | if(err) return next(err); |
| 194 | 0 | res.redirect('/tags/edit'); |
| 195 | }) | |
| 196 | } | |
| 197 | }else{ | |
| 198 | 0 | res.render('notify/notify',{error:'没有这个标签。'}); |
| 199 | 0 | return; |
| 200 | } | |
| 201 | }); | |
| 202 | } | |
| 203 | ||
| 204 | 1 | exports.delete = function(req,res,next){ |
| 205 | 0 | if(!req.session.user){ |
| 206 | 0 | res.render('notify/notify',{error:'你还没有登录。'}); |
| 207 | 0 | return; |
| 208 | } | |
| 209 | 0 | if(!req.session.user.is_admin){ |
| 210 | 0 | res.render('notify/notify',{error:'管理员才能编辑标签。'}); |
| 211 | 0 | return; |
| 212 | } | |
| 213 | 0 | var tag_name = req.params.name; |
| 214 | 0 | Tag.findOne({name:tag_name},function(err,tag){ |
| 215 | 0 | if(err) return next(err); |
| 216 | 0 | if(tag){ |
| 217 | 0 | var proxy = EventProxy.create(); |
| 218 | 0 | var done = function(){ |
| 219 | 0 | tag.remove(function(err){ |
| 220 | 0 | if(err) return next(err); |
| 221 | 0 | res.redirect('/'); |
| 222 | }); | |
| 223 | } | |
| 224 | 0 | proxy.assign('topic_tag_removed','tag_collect_removed',done); |
| 225 | 0 | TopicTag.remove({tag_id:tag._id},function(err){ |
| 226 | 0 | if(err) return next(err); |
| 227 | 0 | proxy.trigger('topic_tag_removed'); |
| 228 | }); | |
| 229 | 0 | TagCollect.remove({tag_id:tag._id},function(err){ |
| 230 | 0 | if(err) return next(err); |
| 231 | 0 | proxy.trigger('tag_collect_removed') |
| 232 | }); | |
| 233 | }else{ | |
| 234 | 0 | res.render('notify/notify',{error:'没有这个标签。'}); |
| 235 | 0 | return; |
| 236 | } | |
| 237 | }); | |
| 238 | } | |
| 239 | ||
| 240 | 1 | exports.collect = function(req,res,next){ |
| 241 | 0 | if(!req.session || !req.session.user){ |
| 242 | 0 | res.send('fobidden!'); |
| 243 | 0 | return; |
| 244 | } | |
| 245 | 0 | var tag_id = req.body.tag_id; |
| 246 | 0 | Tag.findOne({_id: tag_id},function(err,tag){ |
| 247 | 0 | if(err) return next(err); |
| 248 | 0 | if(!tag){ |
| 249 | 0 | res.json({status:'failed'}); |
| 250 | } | |
| 251 | ||
| 252 | 0 | TagCollect.findOne({user_id:req.session.user._id,tag_id:tag._id},function(err,doc){ |
| 253 | 0 | if(err) return next(err); |
| 254 | 0 | if(doc){ |
| 255 | 0 | res.json({status:'success'}); |
| 256 | 0 | return; |
| 257 | } | |
| 258 | 0 | var tag_collect = new TagCollect(); |
| 259 | 0 | tag_collect.user_id = req.session.user._id; |
| 260 | 0 | tag_collect.tag_id = tag._id; |
| 261 | 0 | tag_collect.save(function(err){ |
| 262 | 0 | if(err) return next(err); |
| 263 | //用户更新collect_tag_count | |
| 264 | 0 | user_ctrl.get_user_by_id(req.session.user._id,function(err,user){ |
| 265 | 0 | if(err) return next(err); |
| 266 | 0 | user.collect_tag_count += 1; |
| 267 | 0 | user.save(); |
| 268 | 0 | req.session.user.collect_tag_count += 1; |
| 269 | //标签更新collect_count | |
| 270 | 0 | tag.collect_count += 1; |
| 271 | 0 | tag.save() |
| 272 | 0 | res.json({status:'success'}); |
| 273 | }); | |
| 274 | }); | |
| 275 | }); | |
| 276 | }); | |
| 277 | }; | |
| 278 | ||
| 279 | 1 | exports.de_collect = function(req,res,next){ |
| 280 | 0 | if(!req.session || !req.session.user){ |
| 281 | 0 | res.send('fobidden!'); |
| 282 | 0 | return; |
| 283 | } | |
| 284 | 0 | var tag_id = req.body.tag_id; |
| 285 | 0 | Tag.findOne({_id: tag_id},function(err,tag){ |
| 286 | 0 | if(err) return next(err); |
| 287 | 0 | if(!tag){ |
| 288 | 0 | res.json({status:'failed'}); |
| 289 | } | |
| 290 | 0 | TagCollect.remove({user_id:req.session.user._id,tag_id:tag._id},function(err){ |
| 291 | 0 | if(err) return next(err); |
| 292 | //用户更新collect_tag_count | |
| 293 | 0 | user_ctrl.get_user_by_id(req.session.user._id,function(err,user){ |
| 294 | 0 | if(err) return next(err); |
| 295 | 0 | user.collect_tag_count -= 1; |
| 296 | 0 | user.save() |
| 297 | 0 | req.session.user.collect_tag_count -= 1; |
| 298 | 0 | tag.collect_count -= 1; |
| 299 | 0 | tag.save(); |
| 300 | 0 | res.json({status:'success'}); |
| 301 | }); | |
| 302 | }); | |
| 303 | }); | |
| 304 | }; | |
| 305 | ||
| 306 | 1 | function get_all_tags(cb){ |
| 307 | 0 | Tag.find({},[],{sort:[['order','asc']]},function(err,tags){ |
| 308 | 0 | if(err) return cb(err,[]) |
| 309 | 0 | return cb(err,tags); |
| 310 | }); | |
| 311 | 1 | }; |
| 312 | 1 | function get_tag_by_name(name,cb){ |
| 313 | 0 | Tag.findOne({name:name},function(err,tag){ |
| 314 | 0 | if(err) return cb(err,null); |
| 315 | 0 | return cb(err,tag); |
| 316 | }); | |
| 317 | } | |
| 318 | 1 | function get_tag_by_id(id,cb){ |
| 319 | 0 | Tag.findOne({_id:id},function(err,tag){ |
| 320 | 0 | if(err) return cb(err,null); |
| 321 | 0 | return cb(err,tag); |
| 322 | }); | |
| 323 | } | |
| 324 | 1 | function get_tags_by_ids(ids,cb){ |
| 325 | 0 | Tag.find({_id:{'$in':ids}},function(err,tags){ |
| 326 | 0 | if(err) return cb(err); |
| 327 | 0 | return cb(err,tags); |
| 328 | }); | |
| 329 | } | |
| 330 | 1 | function get_tags_by_query(query,opt,cb){ |
| 331 | 0 | Tag.find(query,[],opt,function(err,tags){ |
| 332 | 0 | if(err) return cb(err); |
| 333 | 0 | return cb(err,tags); |
| 334 | }); | |
| 335 | } | |
| 336 | 1 | exports.get_all_tags = get_all_tags; |
| 337 | 1 | exports.get_tag_by_name = get_tag_by_name; |
| 338 | 1 | exports.get_tag_by_id = get_tag_by_id; |
| 339 | 1 | exports.get_tags_by_ids = get_tags_by_ids; |
| 340 | 1 | exports.get_tags_by_query = get_tags_by_query; |
| Line | Hits | Source |
|---|---|---|
| 1 | /*! | |
| 2 | * nodeclub - controllers/topic.js | |
| 3 | */ | |
| 4 | ||
| 5 | /** | |
| 6 | * Module dependencies. | |
| 7 | */ | |
| 8 | ||
| 9 | 1 | var models = require('../models'); |
| 10 | 1 | var Tag = models.Tag; |
| 11 | 1 | var Topic = models.Topic; |
| 12 | 1 | var TopicTag = models.TopicTag; |
| 13 | 1 | var TopicCollect = models.TopicCollect; |
| 14 | 1 | var Relation = models.Relation; |
| 15 | 1 | var check = require('validator').check; |
| 16 | 1 | var sanitize = require('validator').sanitize; |
| 17 | 1 | var at_ctrl = require('./at'); |
| 18 | 1 | var tag_ctrl = require('./tag'); |
| 19 | 1 | var user_ctrl = require('./user'); |
| 20 | 1 | var reply_ctrl = require('./reply'); |
| 21 | 1 | var EventProxy = require('eventproxy'); |
| 22 | 1 | var Showdown = require('../public/libs/showdown'); |
| 23 | 1 | var Util = require('../libs/util'); |
| 24 | ||
| 25 | /** | |
| 26 | * Topic page | |
| 27 | * | |
| 28 | * @param {HttpRequest} req | |
| 29 | * @param {HttpResponse} res | |
| 30 | * @param {Function} next | |
| 31 | */ | |
| 32 | 1 | exports.index = function (req, res, next) { |
| 33 | 0 | var topic_id = req.params.tid; |
| 34 | 0 | if (topic_id.length !== 24) { |
| 35 | 0 | return res.render('notify/notify', { |
| 36 | error: '此话题不存在或已被删除。' | |
| 37 | }); | |
| 38 | } | |
| 39 | 0 | var events = [ 'topic', 'other_topics', 'no_reply_topics', 'get_relation', '@user']; |
| 40 | 0 | var ep = EventProxy.create(events, function (topic, other_topics, no_reply_topics, relation) { |
| 41 | 0 | res.render('topic/index', { |
| 42 | topic: topic, | |
| 43 | author_other_topics: other_topics, | |
| 44 | no_reply_topics: no_reply_topics, | |
| 45 | relation : relation | |
| 46 | }); | |
| 47 | }); | |
| 48 | ||
| 49 | 0 | ep.on('error', function (err) { |
| 50 | 0 | ep.unbind(); |
| 51 | 0 | next(err); |
| 52 | }); | |
| 53 | ||
| 54 | 0 | ep.once('topic', function(topic) { |
| 55 | 0 | if (topic.content_is_html) { |
| 56 | 0 | return ep.emit('@user'); |
| 57 | } | |
| 58 | 0 | at_ctrl.link_at_who(topic.content, function (err, content) { |
| 59 | 0 | if (err) { |
| 60 | 0 | return ep.emit(err); |
| 61 | } | |
| 62 | 0 | topic.content = Util.xss(Showdown.parse(content)); |
| 63 | 0 | ep.emit('@user'); |
| 64 | }); | |
| 65 | }); | |
| 66 | ||
| 67 | 0 | get_full_topic(topic_id, function (err, message, topic, tags, author, replies) { |
| 68 | 0 | if (err) { |
| 69 | 0 | return ep.emit('error', err); |
| 70 | } | |
| 71 | 0 | if (message) { |
| 72 | 0 | ep.unbind(); |
| 73 | 0 | return res.render('notify/notify', { error: message }); |
| 74 | } | |
| 75 | ||
| 76 | 0 | topic.visit_count += 1; |
| 77 | 0 | topic.save(function (err) { |
| 78 | // format date | |
| 79 | 0 | topic.friendly_create_at = Util.format_date(topic.create_at, true); |
| 80 | 0 | topic.friendly_update_at = Util.format_date(topic.update_at, true); |
| 81 | ||
| 82 | 0 | topic.tags = tags; |
| 83 | 0 | topic.author = author; |
| 84 | 0 | topic.replies = replies; |
| 85 | ||
| 86 | 0 | if (!req.session.user) { |
| 87 | 0 | ep.emit('topic', topic); |
| 88 | } else { | |
| 89 | 0 | var q = { user_id: req.session.user._id, topic_id: topic._id }; |
| 90 | 0 | TopicCollect.findOne(q, function (err, doc) { |
| 91 | 0 | if (err) { |
| 92 | 0 | return ep.emit('error', err); |
| 93 | } | |
| 94 | 0 | topic.in_collection = doc; |
| 95 | 0 | ep.emit('topic', topic); |
| 96 | }); | |
| 97 | } | |
| 98 | }); | |
| 99 | ||
| 100 | //get author's relationship | |
| 101 | 0 | if (!req.session.user || req.session.user._id) { |
| 102 | 0 | ep.emit('get_relation', null); |
| 103 | } else { | |
| 104 | 0 | Relation.findOne({user_id: req.session.user._id, follow_id: topic.author_id}, function (err, relation) { |
| 105 | 0 | if (err) { |
| 106 | 0 | return ep.emit('error', err); |
| 107 | } | |
| 108 | 0 | ep.emit('get_relation', relation); |
| 109 | }); | |
| 110 | } | |
| 111 | ||
| 112 | // get author other topics | |
| 113 | 0 | var options = { limit: 5, sort: [ [ 'last_reply_at', 'desc' ] ]}; |
| 114 | 0 | var query = { author_id: topic.author_id, _id: { '$nin': [ topic._id ] } }; |
| 115 | 0 | get_topics_by_query(query, options, function (err, topics) { |
| 116 | 0 | if (err) { |
| 117 | 0 | return ep.emit('error', err); |
| 118 | } | |
| 119 | 0 | ep.emit('other_topics', topics); |
| 120 | }); | |
| 121 | ||
| 122 | // get no reply topics | |
| 123 | 0 | var options2 = { limit:5, sort: [ ['create_at', 'desc'] ] }; |
| 124 | 0 | get_topics_by_query({ reply_count: 0 }, options2, function(err, topics) { |
| 125 | 0 | if (err) return ep.emit('error', err); |
| 126 | 0 | ep.emit('no_reply_topics', topics); |
| 127 | }); | |
| 128 | }); | |
| 129 | }; | |
| 130 | ||
| 131 | 1 | exports.create = function (req, res, next) { |
| 132 | 0 | if (!req.session.user) { |
| 133 | 0 | res.render('notify/notify', {error: '未登入用户不能发布话题。'}); |
| 134 | 0 | return; |
| 135 | } | |
| 136 | ||
| 137 | 0 | var method = req.method.toLowerCase(); |
| 138 | 0 | if(method == 'get'){ |
| 139 | 0 | tag_ctrl.get_all_tags(function(err,tags){ |
| 140 | 0 | if(err) return next(err); |
| 141 | 0 | res.render('topic/edit',{tags:tags}); |
| 142 | 0 | return; |
| 143 | }); | |
| 144 | } | |
| 145 | ||
| 146 | 0 | if(method == 'post'){ |
| 147 | 0 | var title = sanitize(req.body.title).trim(); |
| 148 | 0 | title = sanitize(title).xss(); |
| 149 | 0 | var content = req.body.t_content; |
| 150 | 0 | var topic_tags=[]; |
| 151 | 0 | if(req.body.topic_tags != ''){ |
| 152 | 0 | topic_tags = req.body.topic_tags.split(','); |
| 153 | } | |
| 154 | ||
| 155 | 0 | if(title == ''){ |
| 156 | 0 | tag_ctrl.get_all_tags(function(err,tags){ |
| 157 | 0 | if(err) return next(err); |
| 158 | 0 | for(var i=0; i<topic_tags.length; i++){ |
| 159 | 0 | for(var j=0; j<tags.length; j++){ |
| 160 | 0 | if(topic_tags[i] == tags[j]._id){ |
| 161 | 0 | tags[j].is_selected = true; |
| 162 | } | |
| 163 | } | |
| 164 | } | |
| 165 | 0 | res.render('topic/edit',{tags:tags, edit_error:'标题不能是空的。', content:content}); |
| 166 | 0 | return; |
| 167 | }); | |
| 168 | 0 | }else if(title.length<10 || title.length>100){ |
| 169 | 0 | tag_ctrl.get_all_tags(function(err,tags){ |
| 170 | 0 | if(err) return next(err); |
| 171 | 0 | for(var i=0; i<topic_tags.length; i++){ |
| 172 | 0 | for(var j=0; j<tags.length; j++){ |
| 173 | 0 | if(topic_tags[i] == tags[j]._id){ |
| 174 | 0 | tags[j].is_selected = true; |
| 175 | } | |
| 176 | } | |
| 177 | } | |
| 178 | 0 | res.render('topic/edit',{tags:tags, edit_error:'标题字数太多或太少', title:title, content:content}); |
| 179 | 0 | return; |
| 180 | }); | |
| 181 | }else{ | |
| 182 | 0 | var topic = new Topic(); |
| 183 | 0 | topic.title = title; |
| 184 | 0 | topic.content = content; |
| 185 | 0 | topic.author_id = req.session.user._id; |
| 186 | 0 | topic.save(function(err){ |
| 187 | 0 | if(err) return next(err); |
| 188 | ||
| 189 | 0 | var proxy = EventProxy.create(); |
| 190 | 0 | var render = function(){ |
| 191 | 0 | res.redirect('/topic/'+topic._id); |
| 192 | } | |
| 193 | ||
| 194 | 0 | proxy.assign('tags_saved','score_saved',render) |
| 195 | //话题可以没有标签 | |
| 196 | 0 | if(topic_tags.length == 0){ |
| 197 | 0 | proxy.emit('tags_saved'); |
| 198 | } | |
| 199 | 0 | var tags_saved_done = function(){ |
| 200 | 0 | proxy.emit('tags_saved'); |
| 201 | }; | |
| 202 | 0 | proxy.after('tag_saved',topic_tags.length,tags_saved_done); |
| 203 | //save topic tags | |
| 204 | 0 | for(var i=0; i<topic_tags.length; i++){ |
| 205 | 0 | (function(i){ |
| 206 | 0 | var topic_tag = new TopicTag(); |
| 207 | 0 | topic_tag.topic_id = topic._id; |
| 208 | 0 | topic_tag.tag_id = topic_tags[i]; |
| 209 | 0 | topic_tag.save(function(err){ |
| 210 | 0 | if(err) return next(err); |
| 211 | 0 | proxy.emit('tag_saved'); |
| 212 | }); | |
| 213 | 0 | tag_ctrl.get_tag_by_id(topic_tags[i],function(err,tag){ |
| 214 | 0 | if(err) return next(err); |
| 215 | 0 | tag.topic_count += 1; |
| 216 | 0 | tag.save(); |
| 217 | }); | |
| 218 | })(i); | |
| 219 | } | |
| 220 | 0 | user_ctrl.get_user_by_id(req.session.user._id,function(err,user){ |
| 221 | 0 | if(err) return next(err); |
| 222 | 0 | user.score += 5; |
| 223 | 0 | user.topic_count += 1; |
| 224 | 0 | user.save(); |
| 225 | 0 | req.session.user.score += 5; |
| 226 | 0 | proxy.emit('score_saved'); |
| 227 | }); | |
| 228 | ||
| 229 | //发送at消息 | |
| 230 | 0 | at_ctrl.send_at_message(content,topic._id,req.session.user._id); |
| 231 | }); | |
| 232 | } | |
| 233 | } | |
| 234 | }; | |
| 235 | ||
| 236 | 1 | exports.edit = function(req,res,next){ |
| 237 | 0 | if(!req.session.user){ |
| 238 | 0 | res.redirect('home'); |
| 239 | 0 | return; |
| 240 | } | |
| 241 | ||
| 242 | 0 | var topic_id = req.params.tid; |
| 243 | 0 | var method = req.method.toLowerCase(); |
| 244 | 0 | if(method == 'get'){ |
| 245 | 0 | if(topic_id.length != 24){ |
| 246 | 0 | res.render('notify/notify',{error: '此话题不存在或已被删除。'}); |
| 247 | 0 | return; |
| 248 | } | |
| 249 | 0 | get_topic_by_id(topic_id,function(err,topic,tags,author){ |
| 250 | 0 | if(!topic){ |
| 251 | 0 | res.render('notify/notify',{error: '此话题不存在或已被删除。'}); |
| 252 | 0 | return; |
| 253 | } | |
| 254 | 0 | if(topic.author_id == req.session.user._id || req.session.user.is_admin){ |
| 255 | 0 | tag_ctrl.get_all_tags(function(err,all_tags){ |
| 256 | 0 | if(err) return next(err); |
| 257 | 0 | for(var i=0; i<tags.length; i++){ |
| 258 | 0 | for(var j=0; j<all_tags.length; j++){ |
| 259 | 0 | if(tags[i].id == all_tags[j].id){ |
| 260 | 0 | all_tags[j].is_selected = true; |
| 261 | } | |
| 262 | } | |
| 263 | } | |
| 264 | ||
| 265 | 0 | res.render('topic/edit',{action:'edit',topic_id:topic._id,title:topic.title,content:topic.content,tags:all_tags}); |
| 266 | }); | |
| 267 | }else{ | |
| 268 | 0 | res.render('notify/notify',{error:'对不起,你不能编辑此话题。'}); |
| 269 | 0 | return; |
| 270 | } | |
| 271 | }); | |
| 272 | } | |
| 273 | 0 | if(method == 'post'){ |
| 274 | 0 | if(topic_id.length != 24){ |
| 275 | 0 | res.render('notify/notify',{error: '此话题不存在或已被删除。'}); |
| 276 | 0 | return; |
| 277 | } | |
| 278 | 0 | get_topic_by_id(topic_id,function(err,topic,tags,author){ |
| 279 | 0 | if(!topic){ |
| 280 | 0 | res.render('notify/notify',{error: '此话题不存在或已被删除。'}); |
| 281 | 0 | return; |
| 282 | } | |
| 283 | 0 | if(topic.author_id == req.session.user._id || req.session.user.is_admin){ |
| 284 | 0 | var title = sanitize(req.body.title).trim(); |
| 285 | 0 | title = sanitize(title).xss(); |
| 286 | 0 | var content = req.body.t_content; |
| 287 | 0 | var topic_tags=[]; |
| 288 | 0 | if(req.body.topic_tags != ''){ |
| 289 | 0 | topic_tags = req.body.topic_tags.split(','); |
| 290 | } | |
| 291 | ||
| 292 | 0 | if(title == ''){ |
| 293 | 0 | tag_ctrl.get_all_tags(function(err,all_tags){ |
| 294 | 0 | if(err) return next(err); |
| 295 | 0 | for(var i=0; i<topic_tags.length; i++){ |
| 296 | 0 | for(var j=0; j<all_tags.length; j++){ |
| 297 | 0 | if(topic_tags[i] == all_tags[j]._id){ |
| 298 | 0 | all_tags[j].is_selected = true; |
| 299 | } | |
| 300 | } | |
| 301 | } | |
| 302 | 0 | res.render('topic/edit',{action:'edit',edit_error:'标题不能是空的。',topic_id:topic._id, content:content,tags:all_tags}); |
| 303 | 0 | return; |
| 304 | }); | |
| 305 | }else{ | |
| 306 | //保存话题 | |
| 307 | //删除topic_tag,标签topic_count减1 | |
| 308 | //保存新topic_tag | |
| 309 | 0 | topic.title = title; |
| 310 | 0 | topic.content = content; |
| 311 | 0 | topic.update_at = new Date(); |
| 312 | 0 | topic.save(function(err){ |
| 313 | 0 | if(err) return next(err); |
| 314 | ||
| 315 | 0 | var proxy = EventProxy.create(); |
| 316 | 0 | var render = function(){ |
| 317 | 0 | res.redirect('/topic/'+topic._id); |
| 318 | } | |
| 319 | 0 | proxy.assign('tags_removed_done','tags_saved_done',render); |
| 320 | ||
| 321 | // 删除topic_tag | |
| 322 | 0 | var tags_removed_done = function(){ |
| 323 | 0 | proxy.emit('tags_removed_done'); |
| 324 | }; | |
| 325 | 0 | TopicTag.find({topic_id:topic._id},function(err,docs){ |
| 326 | 0 | if(docs.length == 0){ |
| 327 | 0 | proxy.emit('tags_removed_done'); |
| 328 | }else{ | |
| 329 | 0 | proxy.after('tag_removed',docs.length,tags_removed_done); |
| 330 | // delete topic tags | |
| 331 | 0 | for(var i=0; i<docs.length; i++){ |
| 332 | 0 | (function(i){ |
| 333 | 0 | docs[i].remove(function(err){ |
| 334 | 0 | if(err) return next(err); |
| 335 | 0 | tag_ctrl.get_tag_by_id(docs[i].tag_id,function(err,tag){ |
| 336 | 0 | if(err) return next(err); |
| 337 | 0 | proxy.emit('tag_removed'); |
| 338 | 0 | tag.topic_count -= 1; |
| 339 | 0 | tag.save(); |
| 340 | }); | |
| 341 | }); | |
| 342 | })(i); | |
| 343 | } | |
| 344 | } | |
| 345 | }); | |
| 346 | ||
| 347 | // 保存topic_tag | |
| 348 | 0 | var tags_saved_done = function(){ |
| 349 | 0 | proxy.emit('tags_saved_done'); |
| 350 | } | |
| 351 | //话题可以没有标签 | |
| 352 | 0 | if(topic_tags.length == 0){ |
| 353 | 0 | proxy.emit('tags_saved_done'); |
| 354 | }else{ | |
| 355 | 0 | proxy.after('tag_saved',topic_tags.length,tags_saved_done); |
| 356 | //save topic tags | |
| 357 | 0 | for(var i=0; i<topic_tags.length; i++){ |
| 358 | 0 | (function(i){ |
| 359 | 0 | var topic_tag = new TopicTag(); |
| 360 | 0 | topic_tag.topic_id = topic._id; |
| 361 | 0 | topic_tag.tag_id = topic_tags[i]; |
| 362 | 0 | topic_tag.save(function(err){ |
| 363 | 0 | if(err) return next(err); |
| 364 | 0 | proxy.emit('tag_saved'); |
| 365 | }); | |
| 366 | 0 | tag_ctrl.get_tag_by_id(topic_tags[i],function(err,tag){ |
| 367 | 0 | if(err) return next(err); |
| 368 | 0 | tag.topic_count += 1; |
| 369 | 0 | tag.save(); |
| 370 | }); | |
| 371 | })(i); | |
| 372 | } | |
| 373 | } | |
| 374 | ||
| 375 | //发送at消息 | |
| 376 | 0 | at_ctrl.send_at_message(content,topic._id,req.session.user._id); |
| 377 | }); | |
| 378 | } | |
| 379 | }else{ | |
| 380 | 0 | res.render('notify/notify',{error:'对不起,你不能编辑此话题。'}); |
| 381 | 0 | return; |
| 382 | } | |
| 383 | }); | |
| 384 | } | |
| 385 | }; | |
| 386 | ||
| 387 | 1 | exports.delete = function(req,res,next){ |
| 388 | //删除话题, 话题作者topic_count减1 | |
| 389 | //删除回复,回复作者reply_count减1 | |
| 390 | //删除topic_tag,标签topic_count减1 | |
| 391 | //删除topic_collect,用户collect_topic_count减1 | |
| 392 | 0 | if(!req.session.user || !req.session.user.is_admin){ |
| 393 | 0 | res.redirect('home'); |
| 394 | 0 | return; |
| 395 | } | |
| 396 | 0 | var topic_id = req.params.tid; |
| 397 | 0 | if(topic_id.length != 24){ |
| 398 | 0 | res.render('notify/notify',{error: '此话题不存在或已被删除。'}); |
| 399 | 0 | return; |
| 400 | } | |
| 401 | 0 | get_topic_by_id(topic_id,function(err,topic,tags,author){ |
| 402 | 0 | if(!topic){ |
| 403 | 0 | res.render('notify/notify',{error: '此话题不存在或已被删除。'}); |
| 404 | 0 | return; |
| 405 | } | |
| 406 | 0 | var proxy = EventProxy.create(); |
| 407 | 0 | var render = function(){ |
| 408 | 0 | res.render('notify/notify',{success: '话题已被删除。'}); |
| 409 | 0 | return; |
| 410 | } | |
| 411 | 0 | proxy.assign('topic_removed',render); |
| 412 | 0 | topic.remove(function(err){ |
| 413 | 0 | proxy.emit('topic_removed'); |
| 414 | }); | |
| 415 | }); | |
| 416 | }; | |
| 417 | ||
| 418 | 1 | exports.top = function (req, res, next) { |
| 419 | 0 | if (!req.session.user.is_admin) { |
| 420 | 0 | res.redirect('home'); |
| 421 | 0 | return; |
| 422 | } | |
| 423 | 0 | var topic_id = req.params.tid; |
| 424 | 0 | var is_top = req.params.is_top; |
| 425 | 0 | if (topic_id.length !== 24) { |
| 426 | 0 | res.render('notify/notify' , {error: '此话题不存在或已被删除。'} ); |
| 427 | 0 | return; |
| 428 | } | |
| 429 | 0 | get_topic_by_id(topic_id, function(err, topic, tags, author) { |
| 430 | 0 | if (!topic) { |
| 431 | 0 | res.render('notify/notify', {error: '此话题不存在或已被删除。'} ); |
| 432 | 0 | return; |
| 433 | } | |
| 434 | 0 | topic.top = is_top; |
| 435 | 0 | var proxy = EventProxy.create(); |
| 436 | 0 | var render = function() { |
| 437 | 0 | var msg = topic.top ? '此话题已经被置顶。' : '此话题已经被取消置顶。'; |
| 438 | 0 | res.render('notify/notify', {success: msg} ); |
| 439 | 0 | return; |
| 440 | } | |
| 441 | 0 | proxy.assign('topic_top', render); |
| 442 | 0 | topic.save( function(err) { |
| 443 | 0 | proxy.emit('topic_top'); |
| 444 | }); | |
| 445 | }); | |
| 446 | }; | |
| 447 | ||
| 448 | 1 | exports.collect = function(req,res,next){ |
| 449 | 0 | if(!req.session || !req.session.user){ |
| 450 | 0 | res.send('forbidden!'); |
| 451 | 0 | return; |
| 452 | } | |
| 453 | 0 | var topic_id = req.body.topic_id; |
| 454 | 0 | Topic.findOne({_id: topic_id},function(err,topic){ |
| 455 | 0 | if(err) return next(err); |
| 456 | 0 | if(!topic){ |
| 457 | 0 | res.json({status:'failed'}); |
| 458 | } | |
| 459 | ||
| 460 | 0 | TopicCollect.findOne({user_id:req.session.user._id,topic_id:topic._id},function(err,doc){ |
| 461 | 0 | if(err) return next(err); |
| 462 | 0 | if(doc){ |
| 463 | 0 | res.json({status:'success'}); |
| 464 | 0 | return; |
| 465 | } | |
| 466 | ||
| 467 | 0 | var topic_collect = new TopicCollect(); |
| 468 | 0 | topic_collect.user_id = req.session.user._id; |
| 469 | 0 | topic_collect.topic_id = topic._id; |
| 470 | 0 | topic_collect.save(function(err){ |
| 471 | 0 | if(err) return next(err); |
| 472 | 0 | res.json({status:'success'}); |
| 473 | }); | |
| 474 | 0 | user_ctrl.get_user_by_id(req.session.user._id,function(err,user){ |
| 475 | 0 | if(err) return next(err); |
| 476 | 0 | user.collect_topic_count += 1; |
| 477 | 0 | user.save() |
| 478 | }); | |
| 479 | ||
| 480 | 0 | req.session.user.collect_topic_count += 1; |
| 481 | 0 | topic.collect_count += 1; |
| 482 | 0 | topic.save(); |
| 483 | }); | |
| 484 | }); | |
| 485 | }; | |
| 486 | ||
| 487 | 1 | exports.de_collect = function(req,res,next){ |
| 488 | 0 | if(!req.session || !req.session.user){ |
| 489 | 0 | res.send('fobidden!'); |
| 490 | 0 | return; |
| 491 | } | |
| 492 | 0 | var topic_id = req.body.topic_id; |
| 493 | 0 | Topic.findOne({_id: topic_id},function(err,topic){ |
| 494 | 0 | if(err) return next(err); |
| 495 | 0 | if(!topic){ |
| 496 | 0 | res.json({status:'failed'}); |
| 497 | } | |
| 498 | 0 | TopicCollect.remove({user_id:req.session.user._id,topic_id:topic._id},function(err){ |
| 499 | 0 | if(err) return next(err); |
| 500 | 0 | res.json({status:'success'}); |
| 501 | }); | |
| 502 | ||
| 503 | 0 | user_ctrl.get_user_by_id(req.session.user._id,function(err,user){ |
| 504 | 0 | if(err) return next(err); |
| 505 | 0 | user.collect_topic_count -= 1; |
| 506 | 0 | user.save(); |
| 507 | }); | |
| 508 | ||
| 509 | 0 | topic.collect_count -= 1; |
| 510 | 0 | topic.save(); |
| 511 | ||
| 512 | 0 | req.session.user.collect_topic_count -= 1; |
| 513 | }); | |
| 514 | }; | |
| 515 | ||
| 516 | // get topic without replies | |
| 517 | 1 | function get_topic_by_id(id, cb) { |
| 518 | 0 | var proxy = EventProxy.create(); |
| 519 | 0 | var done = function (topic, tags, author, last_reply) { |
| 520 | 0 | return cb(null, topic, tags, author, last_reply); |
| 521 | }; | |
| 522 | 0 | proxy.assign('topic', 'tags', 'author', 'last_reply', done); |
| 523 | ||
| 524 | 0 | Topic.findOne({_id: id}, function (err, topic) { |
| 525 | 0 | if (err) { |
| 526 | 0 | return cb(err); |
| 527 | } | |
| 528 | 0 | if (!topic) { |
| 529 | 0 | proxy.emit('topic', null); |
| 530 | 0 | proxy.emit('tags', []); |
| 531 | 0 | proxy.emit('author', null); |
| 532 | 0 | proxy.emit('last_reply', null); |
| 533 | 0 | return; |
| 534 | } | |
| 535 | 0 | proxy.emit('topic', topic); |
| 536 | ||
| 537 | 0 | TopicTag.find({topic_id: topic._id}, function (err, topic_tags) { |
| 538 | 0 | if(err) return cb(err); |
| 539 | 0 | var tags_id = []; |
| 540 | 0 | for(var i=0; i<topic_tags.length; i++){ |
| 541 | 0 | tags_id.push(topic_tags[i].tag_id); |
| 542 | } | |
| 543 | 0 | tag_ctrl.get_tags_by_ids(tags_id,function(err,tags){ |
| 544 | 0 | if(err) return cb(err); |
| 545 | 0 | proxy.emit('tags',tags); |
| 546 | }); | |
| 547 | }); | |
| 548 | ||
| 549 | 0 | user_ctrl.get_user_by_id(topic.author_id, function (err, author) { |
| 550 | 0 | if (err) { |
| 551 | 0 | return cb(err); |
| 552 | } | |
| 553 | 0 | proxy.emit('author', author); |
| 554 | }); | |
| 555 | ||
| 556 | 0 | if (topic.last_reply) { |
| 557 | 0 | reply_ctrl.get_reply_by_id(topic.last_reply, function (err, last_reply) { |
| 558 | 0 | if (err) { |
| 559 | 0 | return cb(err); |
| 560 | } | |
| 561 | 0 | if (!last_reply) { |
| 562 | 0 | proxy.emit('last_reply', null); |
| 563 | 0 | return; |
| 564 | } | |
| 565 | 0 | proxy.emit('last_reply', last_reply); |
| 566 | }); | |
| 567 | } else { | |
| 568 | 0 | proxy.emit('last_reply', null); |
| 569 | } | |
| 570 | }); | |
| 571 | } | |
| 572 | // get topic with replies | |
| 573 | 1 | function get_full_topic(id, cb) { |
| 574 | 0 | var proxy = EventProxy.create(); |
| 575 | 0 | var done = function(topic,tags,author,replies){ |
| 576 | 0 | return cb(null, '', topic,tags,author,replies); |
| 577 | }; | |
| 578 | 0 | proxy.assign('topic','tags','author','replies',done); |
| 579 | ||
| 580 | 0 | Topic.findOne({_id:id},function(err,topic){ |
| 581 | 0 | if(err) return cb(err); |
| 582 | 0 | if(!topic){ |
| 583 | 0 | return cb(null, '此话题不存在或已被删除。'); |
| 584 | } | |
| 585 | 0 | proxy.emit('topic',topic); |
| 586 | ||
| 587 | 0 | TopicTag.find({topic_id: topic._id}, function(err,topic_tags){ |
| 588 | 0 | if(err) return cb(err); |
| 589 | 0 | var tags_id = []; |
| 590 | 0 | for(var i=0; i<topic_tags.length; i++){ |
| 591 | 0 | tags_id.push(topic_tags[i].tag_id); |
| 592 | } | |
| 593 | 0 | tag_ctrl.get_tags_by_ids(tags_id,function(err,tags){ |
| 594 | 0 | if(err) return cb(err); |
| 595 | 0 | proxy.emit('tags',tags); |
| 596 | }); | |
| 597 | }); | |
| 598 | ||
| 599 | 0 | user_ctrl.get_user_by_id(topic.author_id,function(err,author){ |
| 600 | 0 | if(err) return cb(err); |
| 601 | 0 | if(!author){ |
| 602 | 0 | return cb(null, '话题的作者丢了。'); |
| 603 | } | |
| 604 | 0 | proxy.emit('author',author); |
| 605 | }); | |
| 606 | ||
| 607 | 0 | reply_ctrl.get_replies_by_topic_id(topic._id,function(err,replies){ |
| 608 | 0 | if(err) return cb(err); |
| 609 | 0 | proxy.emit('replies',replies); |
| 610 | }); | |
| 611 | ||
| 612 | }); | |
| 613 | ||
| 614 | } | |
| 615 | 1 | function get_topics_by_query(query,opt, cb) { |
| 616 | 0 | Topic.find(query, ['_id'], opt, function (err, docs) { |
| 617 | 0 | if (err) { |
| 618 | 0 | return cb(err); |
| 619 | } | |
| 620 | 0 | if (docs.length === 0) { |
| 621 | 0 | return cb(null, []); |
| 622 | } | |
| 623 | ||
| 624 | 0 | var topics_id = []; |
| 625 | 0 | for (var i = 0; i < docs.length; i++) { |
| 626 | 0 | topics_id.push(docs[i]._id); |
| 627 | } | |
| 628 | ||
| 629 | 0 | var proxy = EventProxy.create(); |
| 630 | 0 | var done = function () { |
| 631 | 0 | return cb(null, topics); |
| 632 | } | |
| 633 | 0 | var topics = []; |
| 634 | 0 | proxy.after('topic_ready', topics_id.length, done); |
| 635 | 0 | for (var i=0; i<topics_id.length; i++) { |
| 636 | 0 | (function(i){ |
| 637 | 0 | get_topic_by_id(topics_id[i], function (err, topic, tags, author, last_reply) { |
| 638 | 0 | if (err) { |
| 639 | 0 | return cb(err); |
| 640 | } | |
| 641 | 0 | topic.tags = tags; |
| 642 | 0 | topic.author = author; |
| 643 | 0 | topic.reply = last_reply; |
| 644 | 0 | topic.friendly_create_at = Util.format_date(topic.create_at,true); |
| 645 | 0 | topics[i] = topic; |
| 646 | 0 | proxy.emit('topic_ready'); |
| 647 | }); | |
| 648 | })(i); | |
| 649 | } | |
| 650 | }); | |
| 651 | } | |
| 652 | 1 | function get_count_by_query(query,cb){ |
| 653 | 0 | Topic.count(query,function(err,count){ |
| 654 | 0 | if(err) return cb(err); |
| 655 | 0 | return cb(err,count); |
| 656 | }); | |
| 657 | } | |
| 658 | ||
| 659 | 1 | exports.get_topic_by_id = get_topic_by_id; |
| 660 | 1 | exports.get_full_topic = get_full_topic; |
| 661 | 1 | exports.get_topics_by_query = get_topics_by_query; |
| 662 | 1 | exports.get_count_by_query = get_count_by_query; |
| Line | Hits | Source |
|---|---|---|
| 1 | /*! | |
| 2 | * nodeclub - topic mention user controller. | |
| 3 | * Copyright(c) 2012 fengmk2 <fengmk2@gmail.com> | |
| 4 | * Copyright(c) 2012 muyuan | |
| 5 | * MIT Licensed | |
| 6 | */ | |
| 7 | ||
| 8 | /** | |
| 9 | * Module dependencies. | |
| 10 | */ | |
| 11 | ||
| 12 | 1 | var models = require('../models'); |
| 13 | 1 | var User = models.User; |
| 14 | 1 | var Message = require('./message'); |
| 15 | 1 | var EventProxy = require('eventproxy'); |
| 16 | ||
| 17 | ||
| 18 | 1 | function searchUsers(text, callback) { |
| 19 | 0 | var results = text.match(/@[a-zA-Z0-9]+/ig); |
| 20 | 0 | var names = []; |
| 21 | 0 | if (results) { |
| 22 | 0 | for (var i = 0, l = results.length; i < l; i++) { |
| 23 | 0 | var s = results[i]; |
| 24 | //remove char @ | |
| 25 | 0 | s = s.slice(1); |
| 26 | 0 | names.push(s); |
| 27 | } | |
| 28 | } | |
| 29 | 0 | if (names.length === 0) { |
| 30 | 0 | return callback(null, names); |
| 31 | } | |
| 32 | ||
| 33 | 0 | User.find({ name: { $in: names } }, callback); |
| 34 | } | |
| 35 | ||
| 36 | 1 | function sendMessageToMentionUsers(text, topicId, authorId, callback) { |
| 37 | 0 | searchUsers(text, function (err, users) { |
| 38 | 0 | if (err || !users || users.length === 0) { |
| 39 | 0 | return callback && callback(err); |
| 40 | } | |
| 41 | 0 | var ep = EventProxy.create(); |
| 42 | 0 | ep.after('sent', users.length, function () { |
| 43 | 0 | callback && callback(); |
| 44 | }); | |
| 45 | 0 | ep.once('error', function (err) { |
| 46 | 0 | ep.unbind(); |
| 47 | 0 | callback && callback(err); |
| 48 | }); | |
| 49 | 0 | users.forEach(function (user) { |
| 50 | 0 | Message.send_at_message(user._id, authorId, topicId, function (err) { |
| 51 | 0 | if (err) { |
| 52 | 0 | return ep.emit('error', err); |
| 53 | } | |
| 54 | 0 | ep.emit('sent'); |
| 55 | }); | |
| 56 | }); | |
| 57 | }); | |
| 58 | } | |
| 59 | ||
| 60 | 1 | function linkUsers(text, callback) { |
| 61 | 0 | searchUsers(text, function (err, users) { |
| 62 | 0 | if (err) { |
| 63 | 0 | return callback(err); |
| 64 | } | |
| 65 | 0 | for (var i = 0, l = users.length; i < l; i++) { |
| 66 | 0 | var name = users[i].name; |
| 67 | 0 | text = text.replace(new RegExp('@' + name, 'gmi'), '@[' + name + '](/user/' + name + ')'); |
| 68 | } | |
| 69 | 0 | return callback(err, text); |
| 70 | }); | |
| 71 | } | |
| 72 | ||
| 73 | 1 | exports.send_at_message = exports.sendMessageToMentionUsers = sendMessageToMentionUsers; |
| 74 | 1 | exports.link_at_who = exports.linkUsers = linkUsers; |
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | var models = require('../models'); |
| 2 | 1 | var Reply = models.Reply; |
| 3 | 1 | var Topic = models.Topic; |
| 4 | 1 | var Message = models.Message; |
| 5 | ||
| 6 | 1 | var check = require('validator').check; |
| 7 | 1 | var sanitize = require('validator').sanitize; |
| 8 | ||
| 9 | 1 | var at_ctrl = require('./at'); |
| 10 | 1 | var user_ctrl = require('./user'); |
| 11 | 1 | var message_ctrl = require('./message'); |
| 12 | ||
| 13 | 1 | var Util = require('../libs/util'); |
| 14 | 1 | var Showdown = require('../public/libs/showdown'); |
| 15 | 1 | var EventProxy = require('eventproxy'); |
| 16 | ||
| 17 | 1 | exports.add = function (req, res, next) { |
| 18 | 0 | if (!req.session || !req.session.user) { |
| 19 | 0 | res.send('forbidden!'); |
| 20 | 0 | return; |
| 21 | } | |
| 22 | ||
| 23 | 0 | var content = req.body.r_content; |
| 24 | 0 | var topic_id = req.params.topic_id; |
| 25 | ||
| 26 | 0 | var str = sanitize(content).trim(); |
| 27 | 0 | if (str === '') { |
| 28 | 0 | res.render('notify/notify', {error: '回复内容不能为空!'}); |
| 29 | 0 | return; |
| 30 | } | |
| 31 | ||
| 32 | 0 | var render = function () { |
| 33 | 0 | res.redirect('/topic/' + topic_id); |
| 34 | }; | |
| 35 | 0 | var proxy = EventProxy.create(); |
| 36 | 0 | proxy.assign('reply_saved', 'message_saved', 'score_saved', render); |
| 37 | ||
| 38 | 0 | var reply = new Reply(); |
| 39 | 0 | reply.content = content; |
| 40 | 0 | reply.topic_id = topic_id; |
| 41 | 0 | reply.author_id = req.session.user._id; |
| 42 | 0 | reply.save(function (err) { |
| 43 | 0 | if (err) { |
| 44 | 0 | return next(err); |
| 45 | } | |
| 46 | 0 | Topic.findOne({_id: topic_id}, function (err, topic) { |
| 47 | 0 | if (err) { |
| 48 | 0 | return next(err); |
| 49 | } | |
| 50 | 0 | topic.last_reply = reply._id; |
| 51 | 0 | topic.last_reply_at = new Date(); |
| 52 | 0 | topic.reply_count += 1; |
| 53 | 0 | topic.save(); |
| 54 | 0 | proxy.emit('reply_saved'); |
| 55 | //发送at消息 | |
| 56 | 0 | at_ctrl.send_at_message(content, topic_id, req.session.user._id); |
| 57 | }); | |
| 58 | }); | |
| 59 | ||
| 60 | 0 | Topic.findOne({_id: topic_id}, function (err, topic) { |
| 61 | 0 | if (err) { |
| 62 | 0 | return next(err); |
| 63 | } | |
| 64 | 0 | if (topic.author_id.toString() === req.session.user._id.toString()) { |
| 65 | 0 | proxy.emit('message_saved'); |
| 66 | } else { | |
| 67 | 0 | message_ctrl.send_reply_message(topic.author_id, req.session.user._id, topic._id); |
| 68 | 0 | proxy.emit('message_saved'); |
| 69 | } | |
| 70 | }); | |
| 71 | ||
| 72 | 0 | user_ctrl.get_user_by_id(req.session.user._id, function (err, user) { |
| 73 | 0 | if (err) { |
| 74 | 0 | return next(err); |
| 75 | } | |
| 76 | 0 | user.score += 5; |
| 77 | 0 | user.reply_count += 1; |
| 78 | 0 | user.save(); |
| 79 | 0 | req.session.user.score += 5; |
| 80 | 0 | proxy.emit('score_saved'); |
| 81 | }); | |
| 82 | }; | |
| 83 | ||
| 84 | 1 | exports.add_reply2 = function (req, res, next) { |
| 85 | 0 | if (!req.session || !req.session.user) { |
| 86 | 0 | res.send('forbidden!'); |
| 87 | 0 | return; |
| 88 | } | |
| 89 | ||
| 90 | 0 | var topic_id = req.params.topic_id; |
| 91 | 0 | var reply_id = req.body.reply_id; |
| 92 | 0 | var content = req.body.r2_content; |
| 93 | ||
| 94 | 0 | var str = sanitize(content).trim(); |
| 95 | 0 | if (str === '') { |
| 96 | 0 | res.send(''); |
| 97 | 0 | return; |
| 98 | } | |
| 99 | ||
| 100 | 0 | var done = function () { |
| 101 | 0 | get_reply_by_id(reply._id, function (err, reply) { |
| 102 | 0 | res.partial('reply/reply2', {object: reply, as: 'reply'}); |
| 103 | }); | |
| 104 | }; | |
| 105 | 0 | var proxy = EventProxy.create(); |
| 106 | 0 | proxy.assign('reply_saved', 'message_saved', done); |
| 107 | ||
| 108 | 0 | var reply = new Reply(); |
| 109 | 0 | reply.content = content; |
| 110 | 0 | reply.topic_id = topic_id; |
| 111 | //标识是二级回复 | |
| 112 | 0 | reply.reply_id = reply_id; |
| 113 | 0 | reply.author_id = req.session.user._id; |
| 114 | 0 | reply.save(function (err) { |
| 115 | 0 | if (err) { |
| 116 | 0 | return next(err); |
| 117 | } | |
| 118 | 0 | Topic.findOne({_id: topic_id}, function (err, topic) { |
| 119 | 0 | if (err) { |
| 120 | 0 | return next(err); |
| 121 | } | |
| 122 | 0 | topic.last_reply = reply._id; |
| 123 | 0 | topic.last_reply_at = new Date(); |
| 124 | 0 | topic.reply_count += 1; |
| 125 | 0 | topic.save(); |
| 126 | 0 | proxy.emit('reply_saved'); |
| 127 | //发送at消息 | |
| 128 | 0 | at_ctrl.send_at_message(content, topic_id, req.session.user._id); |
| 129 | }); | |
| 130 | }); | |
| 131 | ||
| 132 | 0 | Reply.findOne({_id: reply_id}, function (err, reply) { |
| 133 | 0 | if (err) { |
| 134 | 0 | return next(err); |
| 135 | } | |
| 136 | 0 | if (reply.author_id.toString() === req.session.user._id.toString()) { |
| 137 | 0 | proxy.emit('message_saved'); |
| 138 | } else { | |
| 139 | 0 | message_ctrl.send_reply2_message(reply.author_id, req.session.user._id, topic_id); |
| 140 | 0 | proxy.emit('message_saved'); |
| 141 | } | |
| 142 | }); | |
| 143 | }; | |
| 144 | ||
| 145 | 1 | exports.delete = function (req, res, next) { |
| 146 | 0 | var reply_id = req.body.reply_id; |
| 147 | 0 | get_reply_by_id(reply_id, function (err, reply) { |
| 148 | 0 | if (!reply) { |
| 149 | 0 | res.json({status: 'failed'}); |
| 150 | 0 | return; |
| 151 | } | |
| 152 | 0 | if (reply.author_id.toString() === req.session.user._id.toString()) { |
| 153 | 0 | reply.remove(); |
| 154 | 0 | res.json({status: 'success'}); |
| 155 | ||
| 156 | 0 | if (!reply.reply_id) { |
| 157 | 0 | reply.author.score -= 5; |
| 158 | 0 | reply.author.reply_count -= 1; |
| 159 | 0 | reply.author.save(); |
| 160 | } | |
| 161 | } else { | |
| 162 | 0 | res.json({status: 'failed'}); |
| 163 | 0 | return; |
| 164 | } | |
| 165 | ||
| 166 | 0 | Topic.findOne({_id: reply.topic_id}, function (err, topic) { |
| 167 | 0 | if (topic) { |
| 168 | 0 | topic.reply_count -= 1; |
| 169 | 0 | topic.save(); |
| 170 | } | |
| 171 | }); | |
| 172 | }); | |
| 173 | }; | |
| 174 | ||
| 175 | 1 | function get_reply_by_id(id, cb) { |
| 176 | 0 | Reply.findOne({_id: id}, function (err, reply) { |
| 177 | 0 | if (err) { |
| 178 | 0 | return cb(err); |
| 179 | } | |
| 180 | 0 | if (!reply) { |
| 181 | 0 | return cb(err, null); |
| 182 | } | |
| 183 | ||
| 184 | 0 | var author_id = reply.author_id; |
| 185 | 0 | user_ctrl.get_user_by_id(author_id, function (err, author) { |
| 186 | 0 | if (err) { |
| 187 | 0 | return cb(err); |
| 188 | } | |
| 189 | 0 | reply.author = author; |
| 190 | 0 | reply.friendly_create_at = Util.format_date(reply.create_at, true); |
| 191 | 0 | if (reply.content_is_html) { |
| 192 | 0 | return cb(null, reply); |
| 193 | } | |
| 194 | 0 | at_ctrl.link_at_who(reply.content, function (err, str) { |
| 195 | 0 | if (err) { |
| 196 | 0 | return cb(err); |
| 197 | } | |
| 198 | 0 | reply.content = Util.xss(Showdown.parse(str)); |
| 199 | 0 | return cb(err, reply); |
| 200 | }); | |
| 201 | }); | |
| 202 | }); | |
| 203 | } | |
| 204 | ||
| 205 | 1 | function get_replies_by_topic_id(id, cb) { |
| 206 | 0 | Reply.find({topic_id: id}, [], {sort: [['create_at', 'asc']]}, function (err, replies) { |
| 207 | 0 | if (err) { |
| 208 | 0 | return cb(err); |
| 209 | } | |
| 210 | 0 | if (replies.length === 0) { |
| 211 | 0 | return cb(err, []); |
| 212 | } | |
| 213 | ||
| 214 | 0 | var proxy = EventProxy.create(); |
| 215 | 0 | var done = function () { |
| 216 | 0 | var replies2 = []; |
| 217 | 0 | for (var i = replies.length - 1; i >= 0; i--) { |
| 218 | 0 | if (replies[i].reply_id) { |
| 219 | 0 | replies2.push(replies[i]); |
| 220 | 0 | replies.splice(i, 1); |
| 221 | } | |
| 222 | } | |
| 223 | 0 | for (var j = 0; j < replies.length; j++) { |
| 224 | 0 | replies[j].replies = []; |
| 225 | 0 | for (var k = 0; k < replies2.length; k++) { |
| 226 | 0 | var id1 = replies[j]._id; |
| 227 | 0 | var id2 = replies2[k].reply_id; |
| 228 | 0 | if (id1.toString() === id2.toString()) { |
| 229 | 0 | replies[j].replies.push(replies2[k]); |
| 230 | } | |
| 231 | } | |
| 232 | 0 | replies[j].replies.reverse(); |
| 233 | } | |
| 234 | 0 | return cb(err, replies); |
| 235 | }; | |
| 236 | 0 | proxy.after('reply_find', replies.length, done); |
| 237 | 0 | for (var j = 0; j < replies.length; j++) { |
| 238 | 0 | (function (i) { |
| 239 | 0 | var author_id = replies[i].author_id; |
| 240 | 0 | user_ctrl.get_user_by_id(author_id, function (err, author) { |
| 241 | 0 | if (err) { |
| 242 | 0 | return cb(err); |
| 243 | } | |
| 244 | 0 | replies[i].author = author; |
| 245 | 0 | replies[i].friendly_create_at = Util.format_date(replies[i].create_at, true); |
| 246 | 0 | if (replies[i].content_is_html) { |
| 247 | 0 | return proxy.emit('reply_find'); |
| 248 | } | |
| 249 | 0 | at_ctrl.link_at_who(replies[i].content, function (err, str) { |
| 250 | 0 | if (err) { |
| 251 | 0 | return cb(err); |
| 252 | } | |
| 253 | 0 | replies[i].content = Util.xss(Showdown.parse(str)); |
| 254 | 0 | proxy.emit('reply_find'); |
| 255 | }); | |
| 256 | }); | |
| 257 | })(j); | |
| 258 | } | |
| 259 | }); | |
| 260 | } | |
| 261 | 1 | exports.get_reply_by_id = get_reply_by_id; |
| 262 | 1 | exports.get_replies_by_topic_id = get_replies_by_topic_id; |
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | var xss = require('xss'); |
| 2 | ||
| 3 | 1 | exports.format_date = function (date, friendly) { |
| 4 | 0 | var year = date.getFullYear(); |
| 5 | 0 | var month = date.getMonth() + 1; |
| 6 | 0 | var day = date.getDate(); |
| 7 | 0 | var hour = date.getHours(); |
| 8 | 0 | var minute = date.getMinutes(); |
| 9 | 0 | var second = date.getSeconds(); |
| 10 | ||
| 11 | 0 | if (friendly) { |
| 12 | 0 | var now = new Date(); |
| 13 | 0 | var mseconds = -(date.getTime() - now.getTime()); |
| 14 | 0 | var time_std = [ 1000, 60 * 1000, 60 * 60 * 1000, 24 * 60 * 60 * 1000 ]; |
| 15 | 0 | if (mseconds < time_std[3]) { |
| 16 | 0 | if (mseconds > 0 && mseconds < time_std[1]) { |
| 17 | 0 | return Math.floor(mseconds / time_std[0]).toString() + ' 秒前'; |
| 18 | } | |
| 19 | 0 | if (mseconds > time_std[1] && mseconds < time_std[2]) { |
| 20 | 0 | return Math.floor(mseconds / time_std[1]).toString() + ' 分钟前'; |
| 21 | } | |
| 22 | 0 | if (mseconds > time_std[2]) { |
| 23 | 0 | return Math.floor(mseconds / time_std[2]).toString() + ' 小时前'; |
| 24 | } | |
| 25 | } | |
| 26 | } | |
| 27 | ||
| 28 | //month = ((month < 10) ? '0' : '') + month; | |
| 29 | //day = ((day < 10) ? '0' : '') + day; | |
| 30 | 0 | hour = ((hour < 10) ? '0' : '') + hour; |
| 31 | 0 | minute = ((minute < 10) ? '0' : '') + minute; |
| 32 | 0 | second = ((second < 10) ? '0': '') + second; |
| 33 | ||
| 34 | 0 | thisYear = new Date().getFullYear(); |
| 35 | 0 | year = (thisYear === year) ? '' : (year + '-'); |
| 36 | 0 | return year + month + '-' + day + ' ' + hour + ':' + minute; |
| 37 | }; | |
| 38 | ||
| 39 | /** | |
| 40 | * Escape the given string of `html`. | |
| 41 | * | |
| 42 | * @param {String} html | |
| 43 | * @return {String} | |
| 44 | * @api private | |
| 45 | */ | |
| 46 | ||
| 47 | 1 | exports.escape = function(html){ |
| 48 | 0 | var codeSpan = /(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm; |
| 49 | 0 | var codeBlock = /(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g; |
| 50 | 0 | var spans = []; |
| 51 | 0 | var blocks = []; |
| 52 | 0 | var text = String(html).replace(/\r\n/g, '\n') |
| 53 | .replace('/\r/g', '\n'); | |
| 54 | ||
| 55 | 0 | text = '\n\n' + text + '\n\n'; |
| 56 | ||
| 57 | 0 | text = text.replace(codeSpan, function(code) { |
| 58 | 0 | spans.push(code); |
| 59 | 0 | return '`span`'; |
| 60 | }); | |
| 61 | ||
| 62 | 0 | text += '~0'; |
| 63 | ||
| 64 | 0 | return text.replace(codeBlock, function (whole, code, nextChar) { |
| 65 | 0 | blocks.push(code); |
| 66 | 0 | return '\n\tblock' + nextChar; |
| 67 | }) | |
| 68 | .replace(/&(?!\w+;)/g, '&') | |
| 69 | .replace(/</g, '<') | |
| 70 | .replace(/>/g, '>') | |
| 71 | .replace(/"/g, '"') | |
| 72 | .replace(/`span`/g, function() { | |
| 73 | 0 | return spans.shift(); |
| 74 | }) | |
| 75 | .replace(/\n\tblock/g, function() { | |
| 76 | 0 | return blocks.shift(); |
| 77 | }) | |
| 78 | .replace(/~0$/,'') | |
| 79 | .replace(/^\n\n/, '') | |
| 80 | .replace(/\n\n$/, ''); | |
| 81 | }; | |
| 82 | ||
| 83 | /** | |
| 84 | * 过滤XSS攻击代码 | |
| 85 | * | |
| 86 | * @param {string} html | |
| 87 | * @return {string} | |
| 88 | */ | |
| 89 | 1 | exports.xss = function (html) { |
| 90 | 0 | return xss(html); |
| 91 | }; |
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | var mailer = require('nodemailer'); |
| 2 | 1 | var config = require('../conf'); |
| 3 | 1 | var eventproxy = require('eventproxy'); |
| 4 | 1 | var util = require('util'); |
| 5 | 1 | mailer.SMTP = { |
| 6 | host: config.mail_host, | |
| 7 | port: config.mail_port, | |
| 8 | use_authentication: config.mail_use_authentication, | |
| 9 | user: config.mail_user, | |
| 10 | pass: config.mail_pass | |
| 11 | }; | |
| 12 | ||
| 13 | 1 | var SITE_ROOT_URL = 'http://' + config.hostname + (config.port !== 80 ? ':' + config.port : ''); |
| 14 | ||
| 15 | /** | |
| 16 | * keep all the mails to send | |
| 17 | * @type {Array} | |
| 18 | */ | |
| 19 | 1 | var mails = []; |
| 20 | 1 | var timer; |
| 21 | /** | |
| 22 | * control mailer | |
| 23 | * @type {EventProxy} | |
| 24 | */ | |
| 25 | 1 | var mailEvent = eventproxy.create(); |
| 26 | /** | |
| 27 | * when need to send an email, start to check the mails array and send all of emails. | |
| 28 | */ | |
| 29 | 1 | mailEvent.on("getMail", function () { |
| 30 | 0 | if (mails.length === 0) { |
| 31 | 0 | return; |
| 32 | } else { | |
| 33 | //遍历邮件数组,发送每一封邮件,如果有发送失败的,就再压入数组,同时触发mailEvent事件 | |
| 34 | 0 | var failed = false; |
| 35 | 0 | for (var i = 0, len = mails.length; i < len; ++i) { |
| 36 | 0 | var message = mails[i]; |
| 37 | 0 | mails.splice(i, 1); |
| 38 | 0 | i--; |
| 39 | 0 | len--; |
| 40 | 0 | var mail; |
| 41 | 0 | try { |
| 42 | 0 | message.debug = false; |
| 43 | 0 | mail = mailer.send_mail(message, function (error, success) { |
| 44 | 0 | if (error) { |
| 45 | 0 | mails.push(message); |
| 46 | 0 | failed = true; |
| 47 | } | |
| 48 | }); | |
| 49 | } catch(e) { | |
| 50 | 0 | mails.push(message); |
| 51 | 0 | failed = true; |
| 52 | } | |
| 53 | 0 | if (mail) { |
| 54 | 0 | var oldemit = mail.emit; |
| 55 | 0 | mail.emit = function () { |
| 56 | 0 | oldemit.apply(mail, arguments); |
| 57 | }; | |
| 58 | } | |
| 59 | } | |
| 60 | 0 | if (failed) { |
| 61 | 0 | clearTimeout(timer); |
| 62 | 0 | timer = setTimeout(trigger, 60000); |
| 63 | } | |
| 64 | } | |
| 65 | }); | |
| 66 | ||
| 67 | /** | |
| 68 | * trigger email event | |
| 69 | * @return {[type]} | |
| 70 | */ | |
| 71 | 1 | function trigger() { |
| 72 | 0 | mailEvent.trigger("getMail"); |
| 73 | } | |
| 74 | ||
| 75 | /** | |
| 76 | * send an email | |
| 77 | * @param {mail} data [info of an email] | |
| 78 | */ | |
| 79 | 1 | function send_mail(data) { |
| 80 | 0 | if (!data) { |
| 81 | 0 | return; |
| 82 | } | |
| 83 | 0 | if (config.debug) { |
| 84 | 0 | console.log('******************** 在测试环境下,不会真的发送邮件*******************'); |
| 85 | 0 | for (var k in data) { |
| 86 | 0 | console.log('%s: %s', k, data[k]); |
| 87 | } | |
| 88 | 0 | return; |
| 89 | } | |
| 90 | 0 | mails.push(data); |
| 91 | 0 | trigger(); |
| 92 | } | |
| 93 | ||
| 94 | 1 | function send_active_mail(who, token, name, email, cb) { |
| 95 | 0 | var sender = config.mail_sender; |
| 96 | 0 | var to = who; |
| 97 | 0 | var subject = config.name + '社区帐号激活'; |
| 98 | 0 | var html = '<p>您好:<p/>' + |
| 99 | '<p>我们收到您在' + config.name + '社区的注册信息,请点击下面的链接来激活帐户:</p>' + | |
| 100 | '<a href="' + SITE_ROOT_URL + '/active_account?key=' + token + '&name=' + name + '&email=' + email + '">激活链接</a>' + | |
| 101 | '<p>若您没有在' + config.name + '社区填写过注册信息,说明有人滥用了您的电子邮箱,请删除此邮件,我们对给您造成的打扰感到抱歉。</p>' + | |
| 102 | '<p>' +config.name +'社区 谨上。</p>'; | |
| 103 | 0 | var data = { |
| 104 | sender: sender, | |
| 105 | to: to, | |
| 106 | subject: subject, | |
| 107 | html: html | |
| 108 | }; | |
| 109 | 0 | cb (null, true); |
| 110 | 0 | send_mail(data); |
| 111 | } | |
| 112 | 1 | function send_reset_pass_mail(who, token, name, cb) { |
| 113 | 0 | var sender = config.mail_sender; |
| 114 | 0 | var to = who; |
| 115 | 0 | var subject = config.name + '社区密码重置'; |
| 116 | 0 | var html = '<p>您好:<p/>' + |
| 117 | '<p>我们收到您在' + config.name + '社区重置密码的请求,请在24小时内单击下面的链接来重置密码:</p>' + | |
| 118 | '<a href="' + SITE_ROOT_URL + '/reset_pass?key=' + token + '&name=' + name + '">重置密码链接</a>' + | |
| 119 | '<p>若您没有在' + config.name + '社区填写过注册信息,说明有人滥用了您的电子邮箱,请删除此邮件,我们对给您造成的打扰感到抱歉。</p>' + | |
| 120 | '<p>' + config.name +'社区 谨上。</p>'; | |
| 121 | ||
| 122 | 0 | var data = { |
| 123 | sender: sender, | |
| 124 | to: to, | |
| 125 | subject: subject, | |
| 126 | html: html | |
| 127 | }; | |
| 128 | ||
| 129 | 0 | cb (null, true); |
| 130 | 0 | send_mail(data); |
| 131 | } | |
| 132 | ||
| 133 | 1 | function send_reply_mail(who, msg) { |
| 134 | 0 | var sender = config.mail_sender; |
| 135 | 0 | var to = who; |
| 136 | 0 | var subject = config.name + ' 新消息'; |
| 137 | 0 | var html = '<p>您好:<p/>' + |
| 138 | '<p>' + | |
| 139 | '<a href="' + SITE_ROOT_URL + '/user/' + msg.author.name + '">' + msg.author.name + '</a>' + | |
| 140 | ' 在话题 ' + '<a href="' + SITE_ROOT_URL + '/topic/' + msg.topic._id + '">' + msg.topic.title + '</a>' + | |
| 141 | ' 中回复了你。</p>' + | |
| 142 | '<p>若您没有在' + config.name + '社区填写过注册信息,说明有人滥用了您的电子邮箱,请删除此邮件,我们对给您造成的打扰感到抱歉。</p>' + | |
| 143 | '<p>' + config.name +'社区 谨上。</p>'; | |
| 144 | ||
| 145 | 0 | var data = { |
| 146 | sender: sender, | |
| 147 | to: to, | |
| 148 | subject: subject, | |
| 149 | html: html | |
| 150 | }; | |
| 151 | ||
| 152 | 0 | send_mail(data); |
| 153 | ||
| 154 | } | |
| 155 | ||
| 156 | 1 | function send_at_mail(who, msg) { |
| 157 | 0 | var sender = config.mail_sender; |
| 158 | 0 | var to = who; |
| 159 | 0 | var subject = config.name + ' 新消息'; |
| 160 | 0 | var html = '<p>您好:<p/>' + |
| 161 | '<p>' + | |
| 162 | '<a href="' + SITE_ROOT_URL + '/user/' + msg.author.name + '">' + msg.author.name + '</a>' + | |
| 163 | ' 在话题 ' + '<a href="' + SITE_ROOT_URL + '/topic/' + msg.topic._id + '">' + msg.topic.title + '</a>' + | |
| 164 | ' 中@了你。</p>' + | |
| 165 | '<p>若您没有在' + config.name + '社区填写过注册信息,说明有人滥用了您的电子邮箱,请删除此邮件,我们对给您造成的打扰感到抱歉。</p>' + | |
| 166 | '<p>' +config.name +'社区 谨上。</p>'; | |
| 167 | ||
| 168 | 0 | var data = { |
| 169 | sender: sender, | |
| 170 | to: to, | |
| 171 | subject: subject, | |
| 172 | html: html | |
| 173 | }; | |
| 174 | ||
| 175 | 0 | send_mail(data); |
| 176 | } | |
| 177 | ||
| 178 | 1 | exports.send_active_mail = send_active_mail; |
| 179 | 1 | exports.send_reset_pass_mail = send_reset_pass_mail; |
| 180 | 1 | exports.send_reply_mail = send_reply_mail; |
| 181 | 1 | exports.send_at_mail = send_at_mail; |
| Line | Hits | Source |
|---|---|---|
| 1 | /*! | |
| 2 | * nodeclub - site index controller. | |
| 3 | * Copyright(c) 2012 fengmk2 <fengmk2@gmail.com> | |
| 4 | * Copyright(c) 2012 muyuan | |
| 5 | * MIT Licensed | |
| 6 | */ | |
| 7 | ||
| 8 | /** | |
| 9 | * Module dependencies. | |
| 10 | */ | |
| 11 | ||
| 12 | 1 | var tag_ctrl = require('./tag'); |
| 13 | 1 | var user_ctrl = require('./user'); |
| 14 | 1 | var topic_ctrl = require('./topic'); |
| 15 | 1 | var config = require('../conf'); |
| 16 | 1 | var EventProxy = require('eventproxy'); |
| 17 | ||
| 18 | ||
| 19 | 1 | exports.index = function (req, res, next) { |
| 20 | 0 | var page = parseInt(req.query.page, 10) || 1; |
| 21 | 0 | var keyword = req.query.q || ''; // in-site search |
| 22 | 0 | if (Array.isArray(keyword)) { |
| 23 | 0 | keyword = keyword.join(' '); |
| 24 | } | |
| 25 | 0 | keyword = keyword.trim(); |
| 26 | 0 | var limit = config.list_topic_count; |
| 27 | ||
| 28 | 0 | var render = function (tags, topics, hot_topics, stars, tops, no_reply_topics, pages) { |
| 29 | 0 | var all_tags = tags.slice(0); |
| 30 | ||
| 31 | // 计算最热标签 | |
| 32 | 0 | tags.sort(function (tag_a, tag_b) { |
| 33 | 0 | return tag_b.topic_count - tag_a.topic_count; |
| 34 | }); | |
| 35 | 0 | var hot_tags = tags.slice(0, 5); |
| 36 | ||
| 37 | // 计算最新标签 | |
| 38 | 0 | tags.sort(function (tag_a, tag_b) { |
| 39 | 0 | return tag_b.create_at - tag_a.create_at; |
| 40 | }); | |
| 41 | 0 | var recent_tags = tags.slice(0, 5); |
| 42 | 0 | res.render('index', { |
| 43 | tags: all_tags, | |
| 44 | topics: topics, | |
| 45 | current_page: page, | |
| 46 | list_topic_count: limit, | |
| 47 | recent_tags: recent_tags, | |
| 48 | hot_topics: hot_topics, | |
| 49 | stars: stars, | |
| 50 | tops: tops, | |
| 51 | no_reply_topics: no_reply_topics, | |
| 52 | pages: pages, | |
| 53 | keyword: keyword | |
| 54 | }); | |
| 55 | }; | |
| 56 | ||
| 57 | 0 | var proxy = EventProxy.create('tags', 'topics', 'hot_topics', 'stars', 'tops', 'no_reply_topics', 'pages', render); |
| 58 | 0 | proxy.once('error', function (err) { |
| 59 | 0 | proxy.unbind(); |
| 60 | 0 | next(err); |
| 61 | }); | |
| 62 | 0 | tag_ctrl.get_all_tags(function (err, tags) { |
| 63 | 0 | if (err) { |
| 64 | 0 | return proxy.emit('error', err); |
| 65 | } | |
| 66 | 0 | proxy.emit('tags', tags); |
| 67 | }); | |
| 68 | ||
| 69 | 0 | var options = { skip: (page - 1) * limit, limit: limit, sort: [ ['top', 'desc' ], [ 'last_reply_at', 'desc' ] ] }; |
| 70 | 0 | var query = {}; |
| 71 | 0 | if (keyword) { |
| 72 | 0 | keyword = keyword.replace(/[\*\^\&\(\)\[\]\+\?\\]/g, ''); |
| 73 | 0 | query.title = new RegExp(keyword, 'i'); |
| 74 | } | |
| 75 | 0 | topic_ctrl.get_topics_by_query(query, options, function (err, topics) { |
| 76 | 0 | if (err) { |
| 77 | 0 | return proxy.emit('error', err); |
| 78 | } | |
| 79 | 0 | proxy.emit('topics', topics); |
| 80 | }); | |
| 81 | 0 | topic_ctrl.get_topics_by_query({}, { limit: 5, sort: [ [ 'visit_count', 'desc' ] ] }, function (err, hot_topics) { |
| 82 | 0 | if (err) { |
| 83 | 0 | return proxy.emit('error', err); |
| 84 | } | |
| 85 | 0 | proxy.emit('hot_topics', hot_topics); |
| 86 | }); | |
| 87 | 0 | user_ctrl.get_users_by_query({ is_star: true }, { limit: 5 }, function (err, users) { |
| 88 | 0 | if (err) { |
| 89 | 0 | return proxy.emit('error', err); |
| 90 | } | |
| 91 | 0 | proxy.emit('stars', users); |
| 92 | }); | |
| 93 | 0 | user_ctrl.get_users_by_query({}, { limit: 10, sort: [ [ 'score', 'desc' ] ] }, function (err, tops) { |
| 94 | 0 | if (err) { |
| 95 | 0 | return proxy.emit('error', err); |
| 96 | } | |
| 97 | 0 | proxy.emit('tops', tops); |
| 98 | }); | |
| 99 | 0 | topic_ctrl.get_topics_by_query({ reply_count: 0 }, { limit: 5, sort: [ [ 'create_at', 'desc' ] ] }, |
| 100 | function (err, no_reply_topics) { | |
| 101 | 0 | if (err) { |
| 102 | 0 | return proxy.emit('error', err); |
| 103 | } | |
| 104 | 0 | proxy.emit('no_reply_topics', no_reply_topics); |
| 105 | }); | |
| 106 | 0 | topic_ctrl.get_count_by_query(query, function (err, all_topics_count) { |
| 107 | 0 | if (err) { |
| 108 | 0 | return proxy.emit('error', err); |
| 109 | } | |
| 110 | 0 | var pages = Math.ceil(all_topics_count / limit); |
| 111 | 0 | proxy.emit('pages', pages); |
| 112 | }); | |
| 113 | }; |
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | var topic_ctrl = require('./topic'); |
| 2 | ||
| 3 | 1 | var config = require('../conf'); |
| 4 | 1 | var data2xml = require('data2xml'); |
| 5 | 1 | var markdown = require('node-markdown').Markdown; |
| 6 | ||
| 7 | 1 | exports.index = function (req, res, next) { |
| 8 | 0 | if (!config.rss) { |
| 9 | 0 | res.statusCode = 404; |
| 10 | 0 | return res.send('Please set `rss` in config.js'); |
| 11 | } | |
| 12 | 0 | var opt = { limit: config.rss.max_rss_items, sort: [ [ 'create_at','desc' ] ] }; |
| 13 | ||
| 14 | 0 | topic_ctrl.get_topics_by_query({}, opt, function (err, topics) { |
| 15 | 0 | if (err) { |
| 16 | 0 | return next(err); |
| 17 | } | |
| 18 | 0 | var rss_obj = { |
| 19 | _attr: { version: '2.0' }, | |
| 20 | channel: { | |
| 21 | title: config.rss.title, | |
| 22 | link: config.rss.link, | |
| 23 | language: config.rss.language, | |
| 24 | description: config.rss.description, | |
| 25 | item: [] | |
| 26 | }, | |
| 27 | }; | |
| 28 | ||
| 29 | 0 | topics.forEach(function (topic) { |
| 30 | 0 | rss_obj.channel.item.push({ |
| 31 | title: topic.title, | |
| 32 | link: config.rss.link + '/topic/' + topic._id, | |
| 33 | guid: config.rss.link + '/topic/' + topic._id, | |
| 34 | description: markdown(topic.content, true), | |
| 35 | author: topic.author.name, | |
| 36 | pubDate: topic.create_at.toUTCString() | |
| 37 | }); | |
| 38 | }); | |
| 39 | ||
| 40 | 0 | var rss_content = data2xml('rss', rss_obj); |
| 41 | ||
| 42 | 0 | res.contentType('application/xml'); |
| 43 | 0 | res.send(rss_content); |
| 44 | }); | |
| 45 | }; |
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | var fs = require('fs'); |
| 2 | 1 | var path = require('path'); |
| 3 | 1 | var mkdirp = require('mkdirp'); |
| 4 | 1 | var config = require('../conf'); |
| 5 | ||
| 6 | 1 | exports.uploadImage = function (req, res, next) { |
| 7 | 0 | if (!req.session || !req.session.user) { |
| 8 | 0 | res.send({ status: 'forbidden' }); |
| 9 | 0 | return; |
| 10 | } | |
| 11 | 0 | var file = req.files && req.files.userfile; |
| 12 | 0 | if (!file) { |
| 13 | 0 | res.send({ status: 'failed', message: 'no file' }); |
| 14 | 0 | return; |
| 15 | } | |
| 16 | 0 | var uid = req.session.user._id.toString(); |
| 17 | 0 | var userDir = path.join(config.upload_dir, uid); |
| 18 | 0 | mkdirp(userDir, function (err) { |
| 19 | 0 | if (err) { |
| 20 | 0 | return next(err); |
| 21 | } | |
| 22 | 0 | var filename = Date.now() + '_' + file.name; |
| 23 | 0 | var savepath = path.resolve(path.join(userDir, filename)); |
| 24 | 0 | if (savepath.indexOf(path.resolve(userDir)) !== 0) { |
| 25 | 0 | return res.send({status: 'forbidden'}); |
| 26 | } | |
| 27 | 0 | fs.rename(file.path, savepath, function (err) { |
| 28 | 0 | if (err) { |
| 29 | 0 | return next(err); |
| 30 | } | |
| 31 | 0 | var url = '/upload/' + uid + '/' + encodeURIComponent(filename); |
| 32 | 0 | res.send({ status: 'success', url: url }); |
| 33 | }); | |
| 34 | }); | |
| 35 | }; |
| Line | Hits | Source |
|---|---|---|
| 1 | // static page | |
| 2 | 1 | exports.about = function(req,res,next){ |
| 3 | 0 | res.render('static/about'); |
| 4 | }; | |
| 5 | ||
| 6 | 1 | exports.faq = function(req,res,next){ |
| 7 | 0 | res.render('static/faq'); |
| 8 | }; |
| Line | Hits | Source |
|---|---|---|
| 1 | 1 | var models = require('../models'), |
| 2 | User = models.User, | |
| 3 | Topic = models.Topic, | |
| 4 | Reply = models.Reply, | |
| 5 | Relation = models.Relation, | |
| 6 | Message = models.Message; | |
| 7 | ||
| 8 | 1 | var EventProxy = require('eventproxy').EventProxy; |
| 9 | ||
| 10 | 1 | exports.run_site_tools = function(req,res,next){ |
| 11 | 0 | res.send('<h3>The White Castle</h3>'); |
| 12 | }; | |
| 13 | ||
| 14 | // exports.reset_data = function(req,res,next){ | |
| 15 | // Topic.find({},function(err,topics){ | |
| 16 | // for(var i=0; i<topics.length; i++){ | |
| 17 | // var topic = topics[i]; | |
| 18 | // if(topic){ | |
| 19 | // topic.reply_count = 0; | |
| 20 | // topic.save(); | |
| 21 | // } | |
| 22 | // } | |
| 23 | // }); | |
| 24 | // res.end('end'); | |
| 25 | // }; | |
| 26 | ||
| 27 | // exports.cal_data = function(req,res,next){ | |
| 28 | // Reply.find({},function(err,replies){ | |
| 29 | // for(var i=0; i<replies.length; i++){ | |
| 30 | // var reply = replies[i]; | |
| 31 | // if(reply.topic_id){ | |
| 32 | // Topic.update({_id:reply.topic_id},{$inc:{reply_count:1}}).exec(); | |
| 33 | // } | |
| 34 | // } | |
| 35 | // }); | |
| 36 | // res.end('end'); | |
| 37 | // }; |