From c6477935129b523821c287340507e28fe5e3976a Mon Sep 17 00:00:00 2001 From: Baris Usakli Date: Fri, 23 Aug 2013 13:14:36 -0400 Subject: [PATCH] meta config changes, refactors --- app.js | 25 +++--- src/install.js | 12 +-- src/login.js | 10 ++- src/meta.js | 17 +++- src/postTools.js | 27 +++---- src/posts.js | 30 ++++--- src/routes/api.js | 21 ++--- src/routes/authentication.js | 25 +++--- src/routes/user.js | 12 ++- src/threadTools.js | 47 +++++------ src/topics.js | 135 ++++++++++++++++---------------- src/upgrade.js | 44 +++++------ src/user.js | 89 ++++++++++----------- src/webserver.js | 70 ++++++++--------- src/websockets.js | 146 ++++++++++++++++++----------------- 15 files changed, 372 insertions(+), 338 deletions(-) diff --git a/app.js b/app.js index f5a03e401d..8a7603b045 100644 --- a/app.js +++ b/app.js @@ -19,7 +19,8 @@ var fs = require('fs'), winston = require('winston'), pkg = require('./package.json'), - url = require('url'); + url = require('url'), + meta = require('./src/meta.js'); nconf = require('nconf'); // Runtime environment @@ -49,25 +50,20 @@ winston.info('This program comes with ABSOLUTELY NO WARRANTY.'); winston.info('This is free software, and you are welcome to redistribute it under certain conditions.'); winston.info('==='); + + if(nconf.get('upgrade')) { - require('./src/upgrade').upgrade(); + meta.configs.init(function() { + require('./src/upgrade').upgrade(); + }); } else if (!nconf.get('setup') && nconf.get('base_url')) { nconf.set('url', nconf.get('base_url') + (nconf.get('use_port') ? ':' + nconf.get('port') : '') + nconf.get('relative_path') + '/'); nconf.set('upload_url', nconf.get('url') + 'uploads/'); - winston.info('Initializing NodeBB v' + pkg.version + ', on port ' + nconf.get('port') + ', using Redis store at ' + nconf.get('redis:host') + ':' + nconf.get('redis:port') + '.'); winston.info('Base Configuration OK.'); - // TODO: Replace this with nconf-redis - var meta = require('./src/meta.js'); - global.config = {}; - meta.config.get(function(config) { - for(c in config) { - if (config.hasOwnProperty(c)) { - global.config[c] = config[c]; - } - } + meta.configs.init(function() { var categories = require('./src/categories.js'), templates = require('./public/src/templates.js'), @@ -112,7 +108,7 @@ if(nconf.get('upgrade')) { } }); - + winston.info('Hardcoding uid 1 as an admin'); var user = require('./src/user.js'); user.makeAdministrator(1); @@ -127,6 +123,7 @@ if(nconf.get('upgrade')) { setup_categories(); }(global.configuration)); }); + } else { // New install, ask setup questions if (nconf.get('setup')) winston.info('NodeBB Setup Triggered via Command Line'); @@ -150,7 +147,7 @@ if(nconf.get('upgrade')) { ); } } - + process.exit(); }); } \ No newline at end of file diff --git a/src/install.js b/src/install.js index 5312350d7e..1afd20ad69 100644 --- a/src/install.js +++ b/src/install.js @@ -79,16 +79,16 @@ var async = require('async'), port: config.port }, api_url: protocol + '//' + host + (config.use_port ? ':' + config.port : '') + relative_path + '/api/', - relative_path: relative_path + relative_path: relative_path }; server_conf.base_url = protocol + '//' + host; server_conf.relative_path = relative_path; - - meta.config.set('postDelay', 10000); - meta.config.set('minimumPostLength', 8); - meta.config.set('minimumTitleLength', 3); - meta.config.set('imgurClientID', ''); + + meta.configs.set('postDelay', 10000); + meta.configs.set('minimumPostLength', 8); + meta.configs.set('minimumTitleLength', 3); + meta.configs.set('imgurClientID', ''); install.save(server_conf, client_conf, callback); }); diff --git a/src/login.js b/src/login.js index 0adb9311f5..f4ada02e5f 100644 --- a/src/login.js +++ b/src/login.js @@ -24,14 +24,18 @@ var user = require('./user.js'), message: 'invalid-user' }); } - - user.getUserFields(uid, ['password', 'banned'], function(userData) { + + user.getUserFields(uid, ['password', 'banned'], function(err, userData) { + if(err) + return next(err); + if(userData.banned && userData.banned === '1') { return next({ status: "error", message: "user-banned" }); } + bcrypt.compare(password, userData.password, function(err, res) { if(err) { winston.err(err); @@ -41,7 +45,7 @@ var user = require('./user.js'), }); return; } - + if (res) { next({ status: "ok", diff --git a/src/meta.js b/src/meta.js index e12eb4ed9a..cc84b964c1 100644 --- a/src/meta.js +++ b/src/meta.js @@ -5,7 +5,14 @@ var utils = require('./../public/src/utils.js'), fs = require('fs'); (function(Meta) { - Meta.config = { + + Meta.configs = { + init: function(callback) { + Meta.configs.get(function(config) { + Meta.config = config; + callback(); + }); + }, get: function(callback) { RDB.hgetall('config', function(err, config) { if (!err) { @@ -80,8 +87,8 @@ var utils = require('./../public/src/utils.js'), }, function(err, values) { var title; - if (err) title = global.config.title || 'NodeBB'; - else title = (values.title ? values.title + ' | ' : '') + (global.config.title || 'NodeBB'); + if (err) title = Meta.config.title || 'NodeBB'; + else title = (values.title ? values.title + ' | ' : '') + (Meta.config.title || 'NodeBB'); callback(null, title, values.notifCount); }); @@ -110,4 +117,6 @@ var utils = require('./../public/src/utils.js'), } else callback(null); } } -}(exports)); \ No newline at end of file + +}(exports)); + diff --git a/src/postTools.js b/src/postTools.js index 02c1ea70ed..8d8969a768 100644 --- a/src/postTools.js +++ b/src/postTools.js @@ -4,13 +4,14 @@ var RDB = require('./redis.js'), threadTools = require('./threadTools.js'), user = require('./user.js'), async = require('async'), - + utils = require('../public/src/utils'), plugins = require('./plugins'), reds = require('reds'), postSearch = reds.createSearch('nodebbpostsearch'), topicSearch = reds.createSearch('nodebbtopicsearch'), - winston = require('winston'); + winston = require('winston'), + meta = require('./meta.js'); (function(PostTools) { PostTools.isMain = function(pid, tid, callback) { @@ -21,8 +22,8 @@ var RDB = require('./redis.js'), } PostTools.privileges = function(pid, uid, callback) { - //todo: break early if one condition is true - + //todo: break early if one condition is true + function getThreadPrivileges(next) { posts.getPostField(pid, 'tid', function(tid) { threadTools.privileges(tid, uid, function(privileges) { @@ -41,7 +42,7 @@ var RDB = require('./redis.js'), function hasEnoughRep(next) { user.getUserField(uid, 'reputation', function(reputation) { - next(null, reputation >= global.config['privileges:manage_content']); + next(null, reputation >= meta.config['privileges:manage_content']); }); } @@ -95,7 +96,7 @@ var RDB = require('./redis.js'), PostTools.delete = function(uid, pid) { var success = function() { posts.setPostField(pid, 'deleted', 1); - + postSearch.remove(pid); posts.getPostFields(pid, ['tid', 'uid'], function(postData) { @@ -103,7 +104,7 @@ var RDB = require('./redis.js'), user.decrementUserFieldBy(postData.uid, 'postcount', 1, function(err, postcount) { RDB.zadd('users:postcount', postcount, postData.uid); }); - + io.sockets.in('topic_' + postData.tid).emit('event:post_deleted', { pid: pid }); @@ -116,8 +117,8 @@ var RDB = require('./redis.js'), }); } else { posts.getPostField(pid, 'timestamp', function(timestamp) { - topics.updateTimestamp(postData.tid, timestamp); - }); + topics.updateTimestamp(postData.tid, timestamp); + }); } }); }); @@ -141,11 +142,11 @@ var RDB = require('./redis.js'), io.sockets.in('topic_' + postData.tid).emit('event:post_restored', { pid: pid }); - + threadTools.get_latest_undeleted_pid(postData.tid, function(err, pid) { posts.getPostField(pid, 'timestamp', function(timestamp) { topics.updateTimestamp(postData.tid, timestamp); - }); + }); }); postSearch.index(postData.content, pid); @@ -170,7 +171,7 @@ var RDB = require('./redis.js'), if (md && md.length > 0) { var parsedContentDOM = cheerio.load(marked(md)); var domain = nconf.get('url'); - + parsedContentDOM('a').each(function() { this.attr('rel', 'nofollow'); var href = this.attr('href'); @@ -180,7 +181,7 @@ var RDB = require('./redis.js'), if (!isSignature) this.append(' '); } }); - + html = parsedContentDOM.html(); } else { diff --git a/src/posts.js b/src/posts.js index 05f4ae5c59..3115dd8661 100644 --- a/src/posts.js +++ b/src/posts.js @@ -11,6 +11,7 @@ var RDB = require('./redis.js'), plugins = require('./plugins'), reds = require('reds'), nconf = require('nconf'), + meta = require('./meta.js'), postSearch = reds.createSearch('nodebbpostsearch'), winston = require('winston'); @@ -32,7 +33,9 @@ var RDB = require('./redis.js'), } Posts.addUserInfoToPost = function(post, callback) { - user.getUserFields(post.uid, ['username', 'userslug', 'reputation', 'postcount', 'picture', 'signature', 'banned'], function(userData) { + user.getUserFields(post.uid, ['username', 'userslug', 'reputation', 'postcount', 'picture', 'signature', 'banned'], function(err, userData) { + if(err) + return callback(); post.username = userData.username || 'anonymous'; post.userslug = userData.userslug || ''; @@ -43,7 +46,9 @@ var RDB = require('./redis.js'), post.signature = postTools.markdownToHTML(userData.signature, true); if(post.editor !== '') { - user.getUserFields(post.editor, ['username', 'userslug'], function(editorData) { + user.getUserFields(post.editor, ['username', 'userslug'], function(err, editorData) { + if(err) + return callback(); post.editorname = editorData.username; post.editorslug = editorData.userslug; callback(); @@ -146,7 +151,12 @@ var RDB = require('./redis.js'), postData.content = postTools.markdownToHTML(postData.content); if(postData.uploadedImages) { - postData.uploadedImages = JSON.parse(postData.uploadedImages); + try { + postData.uploadedImages = JSON.parse(postData.uploadedImages); + } catch(err) { + postData.uploadedImages = []; + winston.err(err); + } } else { postData.uploadedImages = []; } @@ -184,7 +194,7 @@ var RDB = require('./redis.js'), type: 'error', timeout: 2000, title: 'Content too short', - message: "Please enter a longer post. At least " + config.minimumPostLength + " characters.", + message: "Please enter a longer post. At least " + meta.config.minimumPostLength + " characters.", alert_id: 'post_error' }); } @@ -192,7 +202,7 @@ var RDB = require('./redis.js'), Posts.emitTooManyPostsAlert = function(socket) { socket.emit('event:alert', { title: 'Too many posts!', - message: 'You can only post every '+ config.postDelay/1000 + ' seconds.', + message: 'You can only post every '+ meta.config.postDelay/1000 + ' seconds.', type: 'error', timeout: 2000 }); @@ -203,13 +213,13 @@ var RDB = require('./redis.js'), content = content.trim(); } - if (!content || content.length < config.minimumPostLength) { + if (!content || content.length < meta.config.minimumPostLength) { callback(new Error('content-too-short'), null); return; } user.getUserField(uid, 'lastposttime', function(lastposttime) { - if(Date.now() - lastposttime < config.postDelay) { + if(Date.now() - lastposttime < meta.config.postDelay) { callback(new Error('too-many-posts'), null); return; } @@ -264,7 +274,7 @@ var RDB = require('./redis.js'), 'editor': '', 'edited': 0, 'deleted': 0, - 'uploadedImages': [], + 'uploadedImages': '[]', 'fav_button_class': '', 'fav_star_class': 'icon-star-empty', 'show_banned': 'hide', @@ -310,7 +320,6 @@ var RDB = require('./redis.js'), next(null, []); } else { next(null, uploadedImages); - Posts.setPostField(pid, 'uploadedImages', postData.uploadedImages); } }); }, @@ -321,6 +330,7 @@ var RDB = require('./redis.js'), } }, function(err, results) { postData.uploadedImages = results.uploadedImages; + Posts.setPostField(pid, 'uploadedImages', JSON.stringify(postData.uploadedImages)); postData.content = results.content; callback(postData); }); @@ -338,7 +348,7 @@ var RDB = require('./redis.js'), function uploadPostImages(postData, images, callback) { var imgur = require('./imgur'); - imgur.setClientID(config.imgurClientID); + imgur.setClientID(meta.config.imgurClientID); var uploadedImages = []; diff --git a/src/routes/api.js b/src/routes/api.js index e3eee6e534..d3bbbdc1cd 100644 --- a/src/routes/api.js +++ b/src/routes/api.js @@ -16,19 +16,14 @@ var user = require('./../user.js'), }); app.get('/api/config', function(req, res, next) { - meta.config.getFields(['postDelay', 'minimumTitleLength', 'minimumPostLength', 'imgurClientID'], function(err, metaConfig) { - if(err) return next(); - var clientConfig = require('../../public/config.json'); + var config = require('../../public/config.json'); - for (var attrname in metaConfig) { - clientConfig[attrname] = metaConfig[attrname]; - } - - clientConfig['imgurClientIDSet'] = !!clientConfig['imgurClientID']; - delete clientConfig['imgurClientID']; + config['postDelay'] = meta.config['postDelay']; + config['minimumTitleLength'] = meta.config['minimumTitleLength']; + config['minimumPostLength'] = meta.config['minimumPostLength']; + config['imgurClientIDSet'] = !!meta.config['imgurClientID']; - res.json(200, clientConfig); - }) + res.json(200, config); }); app.get('/api/home', function(req, res) { @@ -48,8 +43,8 @@ var user = require('./../user.js'), } require('async').each(data.categories, iterator, function(err) { - data.motd_class = (config.show_motd === '1' || config.show_motd === undefined) ? '' : 'none'; - data.motd = marked(config.motd || "# NodeBB v " + pkg.version + "\nWelcome to NodeBB, the discussion platform of the future.\n\n Get NodeBB  Fork us on Github  @dcplabs"); + data.motd_class = (meta.config.show_motd === '1' || meta.config.show_motd === undefined) ? '' : 'none'; + data.motd = marked(meta.config.motd || "# NodeBB v " + pkg.version + "\nWelcome to NodeBB, the discussion platform of the future.\n\n Get NodeBB  Fork us on Github  @dcplabs"); res.json(data); }); diff --git a/src/routes/authentication.js b/src/routes/authentication.js index ddd5114859..0d0255becb 100644 --- a/src/routes/authentication.js +++ b/src/routes/authentication.js @@ -6,6 +6,7 @@ passportFacebook = require('passport-facebook').Strategy, login_strategies = [], nconf = require('nconf'), + meta = require('../meta'), user = require('../user'), winston = require('winston'), login_module = require('./../login.js'); @@ -17,10 +18,10 @@ }); })); - if (global.config['social:twitter:key'] && global.config['social:twitter:secret']) { + if (meta.config['social:twitter:key'] && meta.config['social:twitter:secret']) { passport.use(new passportTwitter({ - consumerKey: global.config['social:twitter:key'], - consumerSecret: global.config['social:twitter:secret'], + consumerKey: meta.config['social:twitter:key'], + consumerSecret: meta.config['social:twitter:secret'], callbackURL: nconf.get('url') + 'auth/twitter/callback' }, function(token, tokenSecret, profile, done) { login_module.loginViaTwitter(profile.id, profile.username, profile.photos, function(err, user) { @@ -32,10 +33,10 @@ login_strategies.push('twitter'); } - if (global.config['social:google:id'] && global.config['social:google:secret']) { + if (meta.config['social:google:id'] && meta.config['social:google:secret']) { passport.use(new passportGoogle({ - clientID: global.config['social:google:id'], - clientSecret: global.config['social:google:secret'], + clientID: meta.config['social:google:id'], + clientSecret: meta.config['social:google:secret'], callbackURL: nconf.get('url') + 'auth/google/callback' }, function(accessToken, refreshToken, profile, done) { login_module.loginViaGoogle(profile.id, profile.displayName, profile.emails[0].value, function(err, user) { @@ -47,10 +48,10 @@ login_strategies.push('google'); } - if (global.config['social:facebook:app_id'] && global.config['social:facebook:secret']) { + if (meta.config['social:facebook:app_id'] && meta.config['social:facebook:secret']) { passport.use(new passportFacebook({ - clientID: global.config['social:facebook:app_id'], - clientSecret: global.config['social:facebook:secret'], + clientID: meta.config['social:facebook:app_id'], + clientSecret: meta.config['social:facebook:secret'], callbackURL: nconf.get('url') + 'auth/facebook/callback' }, function(accessToken, refreshToken, profile, done) { login_module.loginViaFacebook(profile.id, profile.displayName, profile.emails[0].value, function(err, user) { @@ -76,7 +77,7 @@ app.use(passport.initialize()); app.use(passport.session()); } - + Auth.get_login_strategies = function() { return login_strategies; @@ -136,7 +137,7 @@ res.send(header + app.create_route('reset') + templates['footer']); }); }); - + app.post('/login', function(req, res, next) { passport.authenticate('local', function(err, user, info) { if(err) { @@ -152,7 +153,7 @@ }); })(req, res, next); }); - + app.post('/register', function(req, res) { user.create(req.body.username, req.body.password, req.body.email, function(err, uid) { diff --git a/src/routes/user.js b/src/routes/user.js index eee9964572..a4c6c38c88 100644 --- a/src/routes/user.js +++ b/src/routes/user.js @@ -281,7 +281,7 @@ var user = require('./../user.js'), }); }); - app.get('/api/users/:userslug/settings', function(req, res) { + app.get('/api/users/:userslug/settings', function(req, res, next) { var callerUID = req.user ? req.user.uid : 0; user.get_uid_by_userslug(req.params.userslug, function(uid) { @@ -294,7 +294,10 @@ var user = require('./../user.js'), res.json(403, { error: 'Not allowed!' }); return; } - user.getUserFields(uid, ['username','userslug','showemail'], function(userData) { + user.getUserFields(uid, ['username','userslug','showemail'], function(err, userData) { + if(err) + return next(err); + if(userData) { if(userData.showemail && userData.showemail === "1") userData.showemail = "checked"; @@ -322,7 +325,10 @@ var user = require('./../user.js'), return; } - user.getUserFields(uid, ['username','userslug'], function(userData) { + user.getUserFields(uid, ['username','userslug'], function(err, userData) { + if(err) + return next(err); + if(userData) { posts.getFavourites(uid, function(err, posts) { if(err) diff --git a/src/threadTools.js b/src/threadTools.js index 4e9efe9311..5bf5321a19 100644 --- a/src/threadTools.js +++ b/src/threadTools.js @@ -7,7 +7,8 @@ var RDB = require('./redis.js'), posts = require('./posts'), reds = require('reds'), topicSearch = reds.createSearch('nodebbtopicsearch'), - winston = require('winston'); + winston = require('winston'), + meta = require('./meta'); (function(ThreadTools) { @@ -17,10 +18,10 @@ var RDB = require('./redis.js'), callback(!!ismember || false); }); } - + ThreadTools.privileges = function(tid, uid, callback) { - //todo: break early if one condition is true - + //todo: break early if one condition is true + function getCategoryPrivileges(next) { topics.getTopicField(tid, 'cid', function(err, cid) { categories.privileges(cid, uid, function(privileges) { @@ -31,10 +32,10 @@ var RDB = require('./redis.js'), function hasEnoughRep(next) { user.getUserField(uid, 'reputation', function(reputation) { - next(null, reputation >= global.config['privileges:manage_topic']); + next(null, reputation >= meta.config['privileges:manage_topic']); }); } - + async.parallel([getCategoryPrivileges, hasEnoughRep], function(err, results) { callback({ @@ -87,7 +88,7 @@ var RDB = require('./redis.js'), ThreadTools.delete = function(tid, uid, callback) { ThreadTools.privileges(tid, uid, function(privileges) { if (privileges.editable || uid === -1) { - + topics.setTopicField(tid, 'deleted', 1); ThreadTools.lock(tid, uid); @@ -110,12 +111,12 @@ var RDB = require('./redis.js'), topics.setTopicField(tid, 'deleted', 0); ThreadTools.unlock(tid, uid); - if (socket) { - io.sockets.in('topic_' + tid).emit('event:topic_restored', { - tid: tid, - status: 'ok' - }); + io.sockets.in('topic_' + tid).emit('event:topic_restored', { + tid: tid, + status: 'ok' + }); + if (socket) { socket.emit('api:topic.restore', { status: 'ok', tid: tid @@ -132,12 +133,12 @@ var RDB = require('./redis.js'), ThreadTools.pin = function(tid, uid, socket) { ThreadTools.privileges(tid, uid, function(privileges) { if (privileges.editable) { - + topics.setTopicField(tid, 'pinned', 1); topics.getTopicField(tid, 'cid', function(err, cid) { RDB.zadd('categories:' + cid + ':tid', Math.pow(2,53), tid); }); - + if (socket) { io.sockets.in('topic_' + tid).emit('event:topic_pinned', { tid: tid, @@ -156,7 +157,7 @@ var RDB = require('./redis.js'), ThreadTools.unpin = function(tid, uid, socket) { ThreadTools.privileges(tid, uid, function(privileges) { if (privileges.editable) { - + topics.setTopicField(tid, 'pinned', 0); topics.getTopicFields(tid, ['cid', 'lastposttime'], function(topicData) { RDB.zadd('categories:' + topicData.cid + ':tid', topicData.lastposttime, tid); @@ -177,17 +178,17 @@ var RDB = require('./redis.js'), } ThreadTools.move = function(tid, cid, socket) { - + topics.getTopicFields(tid, ['cid', 'lastposttime'], function(topicData) { var oldCid = topicData.cid; var multi = RDB.multi(); multi.zrem('categories:' + oldCid + ':tid', tid); multi.zadd('categories:' + cid + ':tid', topicData.lastposttime, tid); - + multi.exec(function(err, result) { - if (!err && result === 1) { + if (!err && result[0] === 1 && result[1] === 1) { topics.setTopicField(tid, 'cid', cid); @@ -258,7 +259,7 @@ var RDB = require('./redis.js'), ThreadTools.notify_followers = function(tid, exceptUid) { async.parallel([ function(next) { - + topics.getTopicField(tid, 'title', function(err, title) { topics.getTeaser(tid, function(err, teaser) { if (!err) { @@ -268,8 +269,8 @@ var RDB = require('./redis.js'), } else next(err); }); }); - - + + }, function(next) { ThreadTools.get_followers(tid, function(err, followers) { @@ -290,14 +291,14 @@ var RDB = require('./redis.js'), var numPosts = posts.length; if(!numPosts) return callback(new Error('no-undeleted-pids-found')); - + while(numPosts--) { if(posts[numPosts].deleted !== '1') { callback(null, posts[numPosts].pid); return; } } - + callback(new Error('no-undeleted-pids-found')); }); } diff --git a/src/topics.js b/src/topics.js index ed437cc2f3..98545bfbfe 100644 --- a/src/topics.js +++ b/src/topics.js @@ -20,7 +20,7 @@ marked.setOptions({ (function(Topics) { - + Topics.getTopicData = function(tid, callback) { RDB.hgetall('topic:' + tid, function(err, data) { @@ -45,15 +45,15 @@ marked.setOptions({ posts.getPostsByTid(tid, start, end, function(postData) { if(Array.isArray(postData) && !postData.length) return callback([]); - + function getFavouritesData(next) { var pids = []; - for(var i=0; i 150) { next({error:'Signature can\'t be longer than 150 characters!'}, false); } else { - next(null, true); - } + next(null, true); + } } - + function isEmailAvailable(next) { if(!data['email']) { return next(null, true); @@ -227,18 +224,18 @@ var utils = require('./../public/src/utils.js'), User.getUserField(uid, 'email', function(email) { if(email !== data['email']) { User.isEmailAvailable(data['email'], function(available) { - if(!available) { + if(!available) { next({error:'Email not available!'}, false); } else { - next(null, true); + next(null, true); } }); } else { - next(null, true); + next(null, true); } }); } - + async.series([isSignatureValid, isEmailAvailable], function(err, results) { if(err) { console.log(err); @@ -261,8 +258,11 @@ var utils = require('./../public/src/utils.js'), if(field === 'email') { var gravatarpicture = User.createGravatarURLFromEmail(data[field]); User.setUserField(uid, 'gravatarpicture', gravatarpicture); - User.getUserFields(uid, ['email', 'picture', 'uploadedpicture'], function(userData) { - RDB.del('email:' + userData['email'] + ':uid'); + User.getUserFields(uid, ['email', 'picture', 'uploadedpicture'], function(err, userData) { + if(err) + return callback(err); + + RDB.del('email:' + userData['email'] + ':uid'); RDB.set('email:' + data['email'] + ':uid', uid); User.setUserField(uid, field, data[field]); if(userData.picture !== userData.uploadedpicture) { @@ -275,9 +275,9 @@ var utils = require('./../public/src/utils.js'), return; } else if(field === 'signature') { data[field] = utils.strip_tags(data[field]); - } + } - User.setUserField(uid, field, data[field]); + User.setUserField(uid, field, data[field]); callback(null); } else { @@ -301,7 +301,7 @@ var utils = require('./../public/src/utils.js'), User.changePassword = function(uid, data, callback) { if(!utils.isPasswordValid(data.newPassword)) { callback({err:'Invalid password!'}); - return; + return; } User.getUserField(uid, 'password', function(user_password) { @@ -343,12 +343,12 @@ var utils = require('./../public/src/utils.js'), User.getUsers = function(set, start, stop, callback) { var data = []; - + RDB.zrevrange(set, start, stop, function(err, uids) { if(err) { return callback(err, null); } - + function iterator(uid, callback) { User.getUserData(uid, function(userData) { if(userData) { @@ -357,7 +357,7 @@ var utils = require('./../public/src/utils.js'), callback(null); }); } - + async.eachSeries(uids, iterator, function(err) { callback(err, data); }); @@ -370,7 +370,7 @@ var utils = require('./../public/src/utils.js'), default: 'identicon', rating: 'pg' }; - + if (!email) { email = ''; options.forcedefault = 'y'; @@ -385,7 +385,7 @@ var utils = require('./../public/src/utils.js'), return; } - bcrypt.genSalt(config.bcrypt_rounds, function(err, salt) { + bcrypt.genSalt(nconf.get('bcrypt_rounds'), function(err, salt) { bcrypt.hash(password, salt, function(err, hash) { callback(hash); }); @@ -421,7 +421,7 @@ var utils = require('./../public/src/utils.js'), User.incrementUserFieldBy(uid, 'postcount', 1, function(err, newpostcount) { RDB.zadd('users:postcount', newpostcount, uid); }); - + User.setUserField(uid, 'lastposttime', timestamp); User.sendPostNotificationToFollowers(uid, tid, pid); @@ -450,9 +450,9 @@ var utils = require('./../public/src/utils.js'), } User.sendConfirmationEmail = function (email) { - if (global.config['email:host'] && global.config['email:port'] && global.config['email:from']) { + if (meta.config['email:host'] && meta.config['email:port'] && meta.config['email:from']) { var confirm_code = utils.generateUUID(), - confirm_link = config.url + 'confirm/' + confirm_code, + confirm_link = nconf.get('url') + 'confirm/' + confirm_code, confirm_email = global.templates['emails/header'] + global.templates['emails/email_confirm'].parse({'CONFIRM_LINK': confirm_link}) + global.templates['emails/footer'], confirm_email_plaintext = global.templates['emails/email_confirm_plaintext'].parse({ 'CONFIRM_LINK': confirm_link }); @@ -466,10 +466,10 @@ var utils = require('./../public/src/utils.js'), RDB.set(confirm_key, email); RDB.expire(confirm_key, expiry_time); - // Send intro email w/ confirm code + // Send intro email w/ confirm code var message = emailjs.message.create({ text: confirm_email_plaintext, - from: config.mailer.from, + from: meta.config.mailer.from, to: email, subject: '[NodeBB] Registration Email Verification', attachment: [ @@ -577,7 +577,7 @@ var utils = require('./../public/src/utils.js'), callback(null); }); } - + async.eachSeries(uids, iterator, function(err) { callback(returnData); }); @@ -625,8 +625,9 @@ var utils = require('./../public/src/utils.js'), RDB.zrevrange('users:joindate', 0, 0, function(err, uid) { RDB.handle(err); - User.getUserFields(uid, ['username', 'userslug'], function(userData) { - socket.emit('user.latest', {userslug: userData.userslug, username: userData.username}); + User.getUserFields(uid, ['username', 'userslug'], function(err, userData) { + if(!err && userData) + socket.emit('user.latest', {userslug: userData.userslug, username: userData.username}); }); }); } @@ -664,7 +665,7 @@ var utils = require('./../public/src/utils.js'), } async.eachSeries(uids, iterator, function(err) { - callback(usernames); + callback(usernames); }); } @@ -683,7 +684,7 @@ var utils = require('./../public/src/utils.js'), } async.eachSeries(uids, iterator, function(err) { - callback(userslugs); + callback(userslugs); }); } @@ -792,7 +793,7 @@ var utils = require('./../public/src/utils.js'), User.reset = { validate: function(socket, code, callback) { - + if (typeof callback !== 'function') { callback = null; } @@ -848,7 +849,7 @@ var utils = require('./../public/src/utils.js'), var message = emailjs.message.create({ text: reset_email_plaintext, - from: config.mailer?config.mailer.from:'localhost@example.org', + from: meta.config.mailer?meta.config.mailer.from:'localhost@example.org', to: email, subject: 'Password Reset Requested', attachment: [ diff --git a/src/webserver.js b/src/webserver.js index e642441d6a..9a57c2aa25 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -10,7 +10,7 @@ var express = require('express'), utils = require('../public/src/utils.js'), pkg = require('../package.json'), fs = require('fs'), - + user = require('./user.js'), categories = require('./categories.js'), posts = require('./posts.js'), @@ -26,7 +26,7 @@ var express = require('express'), (function(app) { var templates = null; - + /** * `options` object requires: req, res * accepts: metaTags @@ -36,13 +36,13 @@ var express = require('express'), { name: 'viewport', content: 'width=device-width, initial-scale=1.0' }, { name: 'content-type', content: 'text/html; charset=UTF-8' }, { name: 'apple-mobile-web-app-capable', content: 'yes' }, - { property: 'og:site_name', content: global.config.title || 'NodeBB' }, + { property: 'og:site_name', content: meta.config.title || 'NodeBB' }, ], metaString = utils.buildMetaTags(defaultMetaTags.concat(options.metaTags || [])), templateValues = { - cssSrc: global.config['theme:src'] || nconf.get('relative_path') + '/vendor/bootstrap/css/bootstrap.min.css', - title: global.config['title'] || 'NodeBB', - browserTitle: global.config['title'] || 'NodeBB', + cssSrc: meta.config['theme:src'] || nconf.get('relative_path') + '/vendor/bootstrap/css/bootstrap.min.css', + title: meta.config['title'] || 'NodeBB', + browserTitle: meta.config['title'] || 'NodeBB', csrf: options.res.locals.csrf_token, relative_path: nconf.get('relative_path'), meta_tags: metaString @@ -83,11 +83,11 @@ var express = require('express'), } auth.initialize(app); - + app.use(function(req, res, next) { - + nconf.set('https', req.secure); - + // Don't bother with session handling for API requests if (/^\/api\//.test(req.url)) return next(); @@ -100,7 +100,7 @@ var express = require('express'), next(); }); - + app.use(app.router); app.use(function(req, res, next) { @@ -118,28 +118,28 @@ var express = require('express'), res.send({ error: 'Not found' }); return; } - + // default to plain-text. send() res.type('txt').send('Not found'); }); app.use(function(err, req, res, next) { - + // we may use properties of the error object // here and next(err) appropriately, or if // we possibly recovered from the error, simply next(). console.error(err.stack); - + res.status(err.status || 500); - + res.json('500', { error: err.message }); - }); - + }); + app.create_route = function(url, tpl) { // to remove return ''; }; - + app.namespace(nconf.get('relative_path'), function() { @@ -149,20 +149,20 @@ var express = require('express'), installRoute.create_routes(app); testBed.create_routes(app); apiRoute.create_routes(app); - - + + // Basic Routes (entirely client-side parsed, goal is to move the rest of the crap in this file into this one section) (function() { var routes = ['login', 'register', 'account', 'recent', 'unread', 'popular', 'active', '403', '404']; - + for (var i=0, ii=routes.length; i 0)) { - + user.getUserField(req.user.uid, 'userslug', function(userslug) { - res.redirect('/users/'+userslug); + res.redirect('/users/'+userslug); }); return; } @@ -174,7 +174,7 @@ var express = require('express'), }(routes[i])); } }()); - + app.get('/', function(req, res) { async.parallel({ @@ -183,9 +183,9 @@ var express = require('express'), req: req, res: res, metaTags: [ - { name: "title", content: global.config.title || 'NodeBB' }, - { name: "description", content: global.config.description || '' }, - { property: 'og:title', content: 'Index | ' + (global.config.title || 'NodeBB') }, + { name: "title", content: meta.config.title || 'NodeBB' }, + { name: "description", content: meta.config.description || '' }, + { property: 'og:title', content: 'Index | ' + (meta.config.title || 'NodeBB') }, { property: "og:type", content: 'website' } ] }, next); @@ -204,7 +204,7 @@ var express = require('express'), ); }) }); - + app.get('/topic/:topic_id/:slug?', function(req, res) { var tid = req.params.topic_id; @@ -214,7 +214,7 @@ var express = require('express'), res.type('text').send(404, "Unable to locate an rss feed at this location."); return; } - + res.type('xml').set('Content-Length', data.length).send(data); }); return; @@ -241,7 +241,7 @@ var express = require('express'), res: res, metaTags: [ { name: "title", content: topicData.topic_name }, - { property: 'og:title', content: topicData.topic_name + ' | ' + (global.config.title || 'NodeBB') }, + { property: 'og:title', content: topicData.topic_name + ' | ' + (meta.config.title || 'NodeBB') }, { property: "og:type", content: 'article' }, { property: "og:url", content: nconf.get('url') + 'topic/' + topicData.slug }, { property: 'og:image', content: topicData.main_posts[0].picture }, @@ -271,7 +271,7 @@ var express = require('express'), app.get('/category/:category_id/:slug?', function(req, res) { var cid = req.params.category_id; - + if (cid.match(/^\d+\.rss$/)) { fs.readFile('feeds/categories/' + cid, function (err, data) { if (err) { @@ -378,20 +378,20 @@ var express = require('express'), templates['footer'] ); }); - }); + }); app.get('/search', function(req, res) { app.build_header({ req: req, res: res }, function(err, header) { res.send(header + app.create_route("search", null, "search") + templates['footer']); }); }); - + app.get('/search/:term', function(req, res) { app.build_header({ req: req, res: res }, function(err, header) { res.send(header + app.create_route("search/"+req.params.term, null, "search") + templates['footer']); }); }); - + app.get('/reindex', function(req, res) { topics.reIndexAll(function(err) { if(err) { @@ -401,7 +401,7 @@ var express = require('express'), } }); }); - + }); }(WebServer)); diff --git a/src/websockets.js b/src/websockets.js index 1496100b4b..cb4f7b68dc 100644 --- a/src/websockets.js +++ b/src/websockets.js @@ -28,7 +28,7 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }), }, plugins = require('./plugins'), winston = require('winston'); - + (function(io) { var users = {}, userSockets = {}, @@ -49,11 +49,11 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }), userSockets[uid] = userSockets[uid] || []; userSockets[uid].push(socket); - + if(uid) { socket.join('uid_' + uid); io.sockets.in('global').emit('api:user.isOnline', isUserOnline(uid)); - + user.getUserField(uid, 'username', function(username) { socket.emit('event:connect', {status: 1, username:username}); }); @@ -61,10 +61,10 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }), }); }); - - + + socket.on('disconnect', function() { - + var index = userSockets[uid].indexOf(socket); if(index !== -1) { userSockets[uid].splice(index, 1); @@ -74,17 +74,17 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }), delete users[sessionID]; if(uid) io.sockets.in('global').emit('api:user.isOnline', isUserOnline(uid)); - } - + } + for(var roomName in rooms) { socket.leave(roomName); if(rooms[roomName][socket.id]) { delete rooms[roomName][socket.id]; - } - - updateRoomBrowsingText(roomName); + } + + updateRoomBrowsingText(roomName); } }); @@ -106,7 +106,7 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }), function getAnonymousCount(roomName) { var clients = io.sockets.clients(roomName); var anonCount = 0; - + for(var i=0; i' + users[i].username + ''; } - - var joiner = anonymousCount + userCount == 1 ? 'is' : 'are', + + var joiner = anonymousCount + userCount == 1 ? 'is' : 'are', userList = anonymousCount > 0 ? usernames.concat(util.format('%d guest%s', anonymousCount, anonymousCount > 1 ? 's' : '')) : usernames, lastUser = userList.length > 1 ? ' and ' + userList.pop() : ''; @@ -146,18 +146,18 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }), } socket.on('event:enter_room', function(data) { - + if (data.leave !== null) { socket.leave(data.leave); } - + socket.join(data.enter); rooms[data.enter] = rooms[data.enter] || {}; if (uid) { rooms[data.enter][socket.id] = uid; - + if (data.leave && rooms[data.leave] && rooms[data.leave][socket.id]) { delete rooms[data.leave][socket.id]; } @@ -168,18 +168,20 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }), updateRoomBrowsingText(data.enter); - if (data.enter != 'admin') + if (data.enter != 'admin') io.sockets.in('admin').emit('api:get_all_rooms', io.sockets.manager.rooms); - + }); // BEGIN: API calls (todo: organize) socket.on('api:updateHeader', function(data) { if(uid) { - user.getUserFields(uid, data.fields, function(fields) { - fields.uid = uid; - socket.emit('api:updateHeader', fields); + user.getUserFields(uid, data.fields, function(err, fields) { + if(!err && fields) { + fields.uid = uid; + socket.emit('api:updateHeader', fields); + } }); } else { @@ -190,9 +192,9 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }), picture: require('gravatar').url('', {s:'24'}, https=nconf.get('https')) }); } - + }); - + socket.on('user.exists', function(data) { user.exists(utils.slugify(data.username), function(exists){ socket.emit('user.exists', {exists: exists}); @@ -233,12 +235,12 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }), socket.on('api:user.get_online_users', function(data) { var returnData = []; - + for(var i=0; i 0) { topics.getTopicData(data.tid, function(topicData) { - if (data.body) + if (data.body) topicData.body = data.body; socket.emit('api:composer.push', { @@ -555,14 +561,16 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }), }); }); } else if (parseInt(data.cid) > 0) { - user.getUserFields(uid, ['username', 'picture'], function(userData) { - socket.emit('api:composer.push', { - tid: 0, - cid: data.cid, - username: userData.username, - picture: userData.picture, - title: undefined - }); + user.getUserFields(uid, ['username', 'picture'], function(err, userData) { + if(!err && userData) { + socket.emit('api:composer.push', { + tid: 0, + cid: data.cid, + username: userData.username, + picture: userData.picture, + title: undefined + }); + } }); } else if (parseInt(data.pid) > 0) { async.parallel([ @@ -630,16 +638,16 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }), socket.on('api:topic.loadMore', function(data, callback) { var start = data.after, end = start + 9; - + topics.getTopicPosts(data.tid, start, end, uid, function(posts) { callback({posts:posts}); }); }); - + socket.on('api:category.loadMore', function(data, callback) { var start = data.after, end = start + 9; - + categories.getCategoryTopics(data.cid, start, end, uid, function(topics) { callback({topics:topics}); }); @@ -653,11 +661,11 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }), callback(latestTopics); }); }); - + socket.on('api:topics.loadMoreUnreadTopics', function(data, callback) { var start = data.after, end = start + 9; - + topics.getUnreadTopics(uid, start, end, function(unreadTopics) { callback(unreadTopics); }); @@ -666,14 +674,14 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }), socket.on('api:users.loadMore', function(data, callback) { var start = data.after, end = start + 19; - + user.getUsers(data.set, start, end, function(err, data) { if(err) { winston.err(err); } else { callback({users:data}); } - }); + }); }); socket.on('api:admin.topics.getMore', function(data, callback) { @@ -685,13 +693,13 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }), socket.on('api:admin.categories.update', function(data) { admin.categories.update(data, socket); }); - + socket.on('api:admin.user.makeAdmin', function(theirid) { if(uid && uid > 0) { admin.user.makeAdmin(uid, theirid, socket); } }); - + socket.on('api:admin.user.removeAdmin', function(theirid) { if(uid && uid > 0) { admin.user.removeAdmin(uid, theirid, socket); @@ -744,5 +752,5 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }), }); }); }); - + }(SocketIO));