offline
+
+ banned
+
Follow
Unfollow
diff --git a/public/templates/admin/redis.tpl b/public/templates/admin/redis.tpl
index e52f021e02..aa127ef893 100644
--- a/public/templates/admin/redis.tpl
+++ b/public/templates/admin/redis.tpl
@@ -16,6 +16,7 @@
Total Connections Received {total_connections_received}
Total Commands Processed {total_commands_processed}
+
Instantaneous Ops. Per Second {instantaneous_ops_per_sec}
Keyspace Hits {keyspace_hits}
Keyspace Misses {keyspace_misses}
diff --git a/public/templates/admin/settings.tpl b/public/templates/admin/settings.tpl
index 82fce61327..ed83c89141 100644
--- a/public/templates/admin/settings.tpl
+++ b/public/templates/admin/settings.tpl
@@ -48,6 +48,16 @@
+
+
\ No newline at end of file
diff --git a/src/admin/user.js b/src/admin/user.js
index 8350af24ec..88ee02f467 100644
--- a/src/admin/user.js
+++ b/src/admin/user.js
@@ -45,7 +45,7 @@ var RDB = require('./../redis.js'),
UserAdmin.deleteUser = function(uid, theirid, socket) {
user.isAdministrator(uid, function(amIAdmin) {
- user.isAdministrator(theirid, function(areTheyAdmin){
+ user.isAdministrator(theirid, function(areTheyAdmin) {
if(amIAdmin && !areTheyAdmin) {
user.delete(theirid, function(data) {
@@ -58,8 +58,39 @@ var RDB = require('./../redis.js'),
});
}
});
+ });
+ };
+
+ UserAdmin.banUser = function(uid, theirid, socket) {
+ user.isAdministrator(uid, function(amIAdmin) {
+ user.isAdministrator(theirid, function(areTheyAdmin) {
+ if(amIAdmin && !areTheyAdmin) {
+ user.ban(theirid, function(err, result) {
-
+ socket.emit('event:alert', {
+ title: 'User Banned',
+ message: 'This user is banned!',
+ type: 'success',
+ timeout: 2000
+ });
+ });
+ }
+ });
+ });
+ };
+
+ UserAdmin.unbanUser = function(uid, theirid, socket) {
+ user.isAdministrator(uid, function(amIAdmin) {
+ if(amIAdmin) {
+ user.unban(theirid, function(err, result) {
+ socket.emit('event:alert', {
+ title: 'User Unbanned',
+ message: 'This user is unbanned!',
+ type: 'success',
+ timeout: 2000
+ });
+ });
+ }
});
};
diff --git a/src/categories.js b/src/categories.js
index 1ce0b886d3..56825f1e57 100644
--- a/src/categories.js
+++ b/src/categories.js
@@ -3,7 +3,8 @@ var RDB = require('./redis.js'),
utils = require('./../public/src/utils.js'),
user = require('./user.js'),
async = require('async'),
- topics = require('./topics.js');
+ topics = require('./topics.js'),
+ winston = require('winston');
(function(Categories) {
@@ -65,7 +66,6 @@ var RDB = require('./redis.js'),
categoryData.moderators = moderators;
categoryData.show_sidebar = 'hidden';
categoryData.no_topics_message = 'show';
-
callback(null, categoryData);
});
} else {
@@ -156,7 +156,7 @@ var RDB = require('./redis.js'),
break;
}
}
- callback(allread);
+ callback(allread);
});
});
}
@@ -187,8 +187,9 @@ var RDB = require('./redis.js'),
Categories.getRecentReplies = function(cid, count, callback) {
RDB.zrevrange('categories:recent_posts:cid:' + cid, 0, (count<10)?10:count, function(err, pids) {
+
if(err) {
- console.log(err);
+ winston.err(err);
callback([]);
return;
}
@@ -198,11 +199,11 @@ var RDB = require('./redis.js'),
return;
}
- posts.getPostSummaryByPids(pids, function(posts) {
- if(posts.length > count) {
- posts = posts.slice(0, count);
+ posts.getPostSummaryByPids(pids, function(postData) {
+ if(postData.length > count) {
+ postData = postData.slice(0, count);
}
- callback(posts);
+ callback(postData);
});
});
}
@@ -222,12 +223,12 @@ var RDB = require('./redis.js'),
if(!err) {
callback(null, 1)
} else {
- console.log(err);
+ winston.err(err);
callback(err, null);
}
});
} else {
- console.log(err);
+ winston.err(err);
callback(err, null);
}
});
@@ -249,7 +250,7 @@ var RDB = require('./redis.js'),
if(err === null)
callback(data);
else
- console.log(err);
+ winston.err(err);
});
}
@@ -278,7 +279,7 @@ var RDB = require('./redis.js'),
}
Categories.hasReadCategory(cid, current_user, function(hasRead) {
- categoryData['badgeclass'] = (parseInt(categoryData.topic_count,10) === 0 || (hasRead && current_user != 0)) ? '' : 'badge-important';
+ categoryData['badgeclass'] = (parseInt(categoryData.topic_count, 10) === 0 || (hasRead && current_user != 0)) ? '' : 'badge-important';
categories.push(categoryData);
callback(null);
@@ -288,7 +289,7 @@ var RDB = require('./redis.js'),
async.eachSeries(cids, getCategory, function(err) {
if(err) {
- console.log(err);
+ winston.err(err);
callback(null);
return;
}
diff --git a/src/favourites.js b/src/favourites.js
index c2cf33b391..894a301311 100644
--- a/src/favourites.js
+++ b/src/favourites.js
@@ -13,11 +13,6 @@ var RDB = require('./redis.js'),
type: 'error',
timeout: 5000
});
-
- socket.emit('api:posts.favourite', {
- status: 'error',
- pid: pid
- });
return;
}
@@ -28,15 +23,19 @@ var RDB = require('./redis.js'),
RDB.sadd('pid:' + pid + ':users_favourited', uid);
RDB.hincrby('post:' + pid, 'reputation', 1);
- if (uid !== uid_of_poster)
- user.incrementUserFieldBy(uid_of_poster, 'reputation', 1);
+ if (uid !== uid_of_poster) {
+ user.incrementUserFieldBy(uid_of_poster, 'reputation', 1, function(err, newreputation) {
+ RDB.zadd('users:reputation', newreputation, uid_of_poster);
+ });
+ }
if (room_id) {
io.sockets.in(room_id).emit('event:rep_up', {uid: uid !== uid_of_poster ? uid_of_poster : 0, pid: pid});
}
socket.emit('api:posts.favourite', {
- status: 'ok'
+ status: 'ok',
+ pid: pid
});
}
});
@@ -63,12 +62,20 @@ var RDB = require('./redis.js'),
RDB.srem('pid:' + pid + ':users_favourited', uid);
RDB.hincrby('post:' + pid, 'reputation', -1);
- if (uid !== uid_of_poster)
- user.incrementUserFieldBy(uid_of_poster, 'reputation', -1);
+ if (uid !== uid_of_poster) {
+ user.incrementUserFieldBy(uid_of_poster, 'reputation', -1, function(err, newreputation) {
+ RDB.zadd('users:reputation', newreputation, uid_of_poster);
+ });
+ }
if (room_id) {
io.sockets.in(room_id).emit('event:rep_down', {uid: uid !== uid_of_poster ? uid_of_poster : 0, pid: pid});
}
+
+ socket.emit('api:posts.unfavourite', {
+ status: 'ok',
+ pid: pid
+ });
}
});
});
diff --git a/src/feed.js b/src/feed.js
index e012850d4c..bdbab1d1e7 100644
--- a/src/feed.js
+++ b/src/feed.js
@@ -4,12 +4,13 @@
posts = require('./posts.js'),
topics = require('./topics.js'),
fs = require('fs'),
- rss = require('node-rss');
+ rss = require('node-rss'),
+ winston = require('winston');
function saveFeed(location, feed) {
fs.writeFile(location, rss.getFeedXML(feed), function (err) {
if(err) {
- console.log(err);
+ winston.err(err);
}
});
}
@@ -32,7 +33,7 @@
var cache_time_in_seconds = 60;
topics.getTopicWithPosts(tid, 0, function(err, topicData) {
- if (err) console.log('Error: Problem saving topic RSS feed', err);
+ if (err) winston.error('Problem saving topic RSS feed', err.stack);
var location = '/topic/' + topicData.slug,
xml_url = '/topic/' + tid + '.rss';
@@ -69,7 +70,7 @@
Feed.updateCategory = function(cid) {
categories.getCategoryById(cid, 0, function(err, categoryData) {
if (err) {
- console.log('Error: Could not update RSS feed for category ' + cid);
+ winston.error('Could not update RSS feed for category ' + cid, err.stack);
return;
}
diff --git a/src/install.js b/src/install.js
index c9301ee8f1..b6b83798d7 100644
--- a/src/install.js
+++ b/src/install.js
@@ -3,6 +3,7 @@ var async = require('async'),
fs = require('fs'),
url = require('url'),
path = require('path'),
+ meta = require('./meta'),
install = {
questions: [
'base_url|Publically accessible URL of this installation? (http://localhost)',
@@ -78,12 +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;
server_conf.imgurClientID = '';
+
+ meta.config.set('postDelay', 10000);
+ meta.config.set('minimumPostLength', 8);
+ meta.config.set('minimumTitleLength', 3);
install.save(server_conf, client_conf, callback);
});
diff --git a/src/login.js b/src/login.js
index b0c8716660..0adb9311f5 100644
--- a/src/login.js
+++ b/src/login.js
@@ -2,7 +2,8 @@
var user = require('./user.js'),
bcrypt = require('bcrypt'),
RDB = require('./redis.js'),
- path = require('path');
+ path = require('path'),
+ winston = require('winston');
(function(Login){
@@ -24,10 +25,16 @@ var user = require('./user.js'),
});
}
- user.getUserField(uid, 'password', function(user_password) {
- bcrypt.compare(password, user_password, function(err, res) {
+ user.getUserFields(uid, ['password', 'banned'], function(userData) {
+ if(userData.banned && userData.banned === '1') {
+ return next({
+ status: "error",
+ message: "user-banned"
+ });
+ }
+ bcrypt.compare(password, userData.password, function(err, res) {
if(err) {
- console.log(err);
+ winston.err(err);
next({
status: "error",
message: 'bcrypt compare error'
diff --git a/src/meta.js b/src/meta.js
index 87c11fe3f0..772230d94a 100644
--- a/src/meta.js
+++ b/src/meta.js
@@ -9,6 +9,7 @@ var utils = require('./../public/src/utils.js'),
get: function(callback) {
RDB.hgetall('config', function(err, config) {
if (!err) {
+ config = config || {};
config.status = 'ok';
callback(config);
} else {
@@ -18,9 +19,13 @@ var utils = require('./../public/src/utils.js'),
}
});
},
+ getFields: function(fields, callback) {
+ RDB.hmgetObject('config', fields, callback);
+ },
set: function(field, value, callback) {
RDB.hset('config', field, value, function(err, res) {
- callback(err);
+ if(callback)
+ callback(err, res);
});
},
remove: function(field) {
@@ -76,7 +81,7 @@ var utils = require('./../public/src/utils.js'),
var title;
if (err) title = global.config.title || 'NodeBB';
- else title = (values.notifCount > 0 ? '(' + values.notifCount + ') ' : '') + (values.title ? values.title + ' | ' : '') + global.config.title || 'NodeBB';
+ else title = (values.notifCount > 0 ? '(' + values.notifCount + ') ' : '') + (values.title ? values.title + ' | ' : '') + (global.config.title || 'NodeBB');
callback(null, title);
});
diff --git a/src/plugins.js b/src/plugins.js
index f842b2fe12..62de6dc741 100644
--- a/src/plugins.js
+++ b/src/plugins.js
@@ -2,12 +2,13 @@ var fs = require('fs'),
path = require('path'),
RDB = require('./redis.js'),
async = require('async'),
+ winston = require('winston'),
plugins = {
libraries: [],
loadedHooks: {},
init: function() {
if (this.initialized) return;
- if (global.env === 'development') console.log('Info: [plugins] Initializing plugins system');
+ if (global.env === 'development') winston.info('[plugins] Initializing plugins system');
var _self = this;
@@ -32,12 +33,12 @@ var fs = require('fs'),
_self.registerHook(pluginData.id, pluginData.hooks[x]);
}
}
- if (global.env === 'development') console.log('Info: [plugins] Loaded plugin: ' + pluginData.id);
+ if (global.env === 'development') winston.info('[plugins] Loaded plugin: ' + pluginData.id);
next();
});
} else {
- if (global.env === 'development') console.log('Info: [plugins] Plugin \'' + plugin + '\' not found');
+ if (global.env === 'development') winston.info('[plugins] Plugin \'' + plugin + '\' not found');
next(); // Ignore this plugin silently
}
})
@@ -45,11 +46,11 @@ var fs = require('fs'),
}
], function(err) {
if (err) {
- if (global.env === 'development') console.log('Info: [plugins] NodeBB encountered a problem while loading plugins', err.message);
+ if (global.env === 'development') winston.info('[plugins] NodeBB encountered a problem while loading plugins', err.message);
return;
}
- if (global.env === 'development') console.log('Info: [plugins] Plugins OK');
+ if (global.env === 'development') winston.info('[plugins] Plugins OK');
});
},
initialized: false,
@@ -66,7 +67,7 @@ var fs = require('fs'),
if (data.hook && data.method) {
_self.loadedHooks[data.hook] = _self.loadedHooks[data.hook] || [];
_self.loadedHooks[data.hook].push([id, data.method]);
- if (global.env === 'development') console.log('Info: [plugins] Hook registered: ' + data.hook + ' will call ' + id);
+ if (global.env === 'development') winston.info('[plugins] Hook registered: ' + data.hook + ' will call ' + id);
} else return;
},
fireHook: function(hook, args, callback) {
@@ -75,7 +76,7 @@ var fs = require('fs'),
hookList = this.loadedHooks[hook];
if (hookList && Array.isArray(hookList)) {
- if (global.env === 'development') console.log('Info: [plugins] Firing hook: \'' + hook + '\'');
+ if (global.env === 'development') winston.info('[plugins] Firing hook: \'' + hook + '\'');
var hookType = hook.split(':')[0];
switch(hookType) {
case 'filter':
@@ -94,7 +95,7 @@ var fs = require('fs'),
}
}, function(err) {
if (err) {
- if (global.env === 'development') console.log('Info: [plugins] Problem executing hook: ' + hook);
+ if (global.env === 'development') winston.info('[plugins] Problem executing hook: ' + hook);
}
callback(returnVal);
@@ -109,7 +110,7 @@ var fs = require('fs'),
) {
_self.libraries[hookObj[0]][hookObj[1]].apply(_self.libraries[hookObj[0]], args);
} else {
- if (global.env === 'development') console.log('Info: [plugins] Expected method \'' + hookObj[1] + '\' in plugin \'' + hookObj[0] + '\' not found, skipping.');
+ if (global.env === 'development') winston.info('[plugins] Expected method \'' + hookObj[1] + '\' in plugin \'' + hookObj[0] + '\' not found, skipping.');
}
});
break;
@@ -129,13 +130,13 @@ var fs = require('fs'),
toggleActive: function(id, callback) {
this.isActive(id, function(err, active) {
if (err) {
- if (global.env === 'development') console.log('Info: [plugins] Could not toggle active state on plugin \'' + id + '\'');
+ if (global.env === 'development') winston.info('[plugins] Could not toggle active state on plugin \'' + id + '\'');
return;
}
RDB[(active ? 'srem' : 'sadd')]('plugins:active', id, function(err, success) {
if (err) {
- if (global.env === 'development') console.log('Info: [plugins] Could not toggle active state on plugin \'' + id + '\'');
+ if (global.env === 'development') winston.info('[plugins] Could not toggle active state on plugin \'' + id + '\'');
return;
}
diff --git a/src/postTools.js b/src/postTools.js
index 1340fd7438..b66886c912 100644
--- a/src/postTools.js
+++ b/src/postTools.js
@@ -9,7 +9,8 @@ var RDB = require('./redis.js'),
plugins = require('./plugins'),
reds = require('reds'),
postSearch = reds.createSearch('nodebbpostsearch'),
- topicSearch = reds.createSearch('nodebbtopicsearch');
+ topicSearch = reds.createSearch('nodebbtopicsearch'),
+ winston = require('winston');
(function(PostTools) {
PostTools.isMain = function(pid, tid, callback) {
@@ -99,7 +100,9 @@ var RDB = require('./redis.js'),
posts.getPostFields(pid, ['tid', 'uid'], function(postData) {
- user.decrementUserFieldBy(postData.uid, 'postcount', 1);
+ 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
@@ -109,7 +112,7 @@ var RDB = require('./redis.js'),
threadTools.get_latest_undeleted_pid(postData.tid, function(err, pid) {
if (err && err.message === 'no-undeleted-pids-found') {
threadTools.delete(postData.tid, -1, function(err) {
- if (err) console.log('Error: Could not delete topic (tid: ' + postData.tid + ')');
+ if (err) winston.error('Could not delete topic (tid: ' + postData.tid + ')', err.stack);
});
} else {
posts.getPostField(pid, 'timestamp', function(timestamp) {
diff --git a/src/posts.js b/src/posts.js
index 932c9e7835..12d6d95c49 100644
--- a/src/posts.js
+++ b/src/posts.js
@@ -10,12 +10,12 @@ var RDB = require('./redis.js'),
async = require('async'),
plugins = require('./plugins'),
reds = require('reds'),
- postSearch = reds.createSearch('nodebbpostsearch');
+ nconf = require('nconf'),
+ postSearch = reds.createSearch('nodebbpostsearch'),
+ winston = require('winston');
(function(Posts) {
- Posts.minimumPostLength = 8;
-
Posts.getPostsByTid = function(tid, start, end, callback) {
RDB.lrange('tid:' + tid + ':posts', start, end, function(err, pids) {
@@ -32,12 +32,13 @@ var RDB = require('./redis.js'),
}
Posts.addUserInfoToPost = function(post, callback) {
- user.getUserFields(post.uid, ['username', 'userslug', 'reputation', 'postcount', 'picture', 'signature'], function(userData) {
+ user.getUserFields(post.uid, ['username', 'userslug', 'reputation', 'postcount', 'picture', 'signature', 'banned'], function(userData) {
post.username = userData.username || 'anonymous';
post.userslug = userData.userslug || '';
post.user_rep = userData.reputation || 0;
post.user_postcount = userData.postcount || 0;
+ post.user_banned = userData.banned || '0';
post.picture = userData.picture || require('gravatar').url('', {}, https=global.nconf.get('https'));
post.signature = postTools.markdownToHTML(userData.signature, true);
@@ -55,7 +56,7 @@ var RDB = require('./redis.js'),
Posts.getPostSummaryByPids = function(pids, callback) {
- var returnData = [];
+ var posts = [];
function getPostSummary(pid, callback) {
Posts.getPostFields(pid, ['pid', 'tid', 'content', 'uid', 'timestamp', 'deleted'], function(postData) {
@@ -70,7 +71,7 @@ var RDB = require('./redis.js'),
postData.content = utils.strip_tags(postTools.markdownToHTML(postData.content));
postData.topicSlug = topicSlug;
- returnData.push(postData);
+ posts.push(postData);
callback(null);
});
});
@@ -80,13 +81,19 @@ var RDB = require('./redis.js'),
async.eachSeries(pids, getPostSummary, function(err) {
if(!err) {
- callback(returnData);
+ callback(posts);
} else {
console.log(err);
}
});
};
+ Posts.filterBannedPosts = function(posts) {
+ return posts.filter(function(post) {
+ return post.user_banned === '0';
+ });
+ }
+
Posts.getPostData = function(pid, callback) {
RDB.hgetall('post:' + pid, function(err, data) {
if(err === null) {
@@ -174,7 +181,7 @@ var RDB = require('./redis.js'),
type: 'error',
timeout: 2000,
title: 'Content too short',
- message: "Please enter a longer post. At least " + Posts.minimumPostLength + " characters.",
+ message: "Please enter a longer post. At least " + config.minimumPostLength + " characters.",
alert_id: 'post_error'
});
}
@@ -182,7 +189,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.post_delay / 1000) + ' seconds.',
+ message: 'You can only post every '+ config.postDelay/1000 + ' seconds.',
type: 'error',
timeout: 2000
});
@@ -192,15 +199,14 @@ var RDB = require('./redis.js'),
if(content) {
content = content.trim();
}
-
- if (!content || content.length < Posts.minimumPostLength) {
+
+ if (!content || content.length < config.minimumPostLength) {
callback(new Error('content-too-short'), null);
return;
}
user.getUserField(uid, 'lastposttime', function(lastposttime) {
-
- if(Date.now() - lastposttime < config.post_delay) {
+ if(Date.now() - lastposttime < config.postDelay) {
callback(new Error('too-many-posts'), null);
return;
}
@@ -300,7 +306,7 @@ var RDB = require('./redis.js'),
uploadPostImages(postData, images, function(err, uploadedImages) {
if(err) {
- console.log('Uploading images failed!');
+ winston.error('Uploading images failed!', err.stack);
} else {
postData.uploadedImages = JSON.stringify(uploadedImages);
Posts.setPostField(pid, 'uploadedImages', postData.uploadedImages);
diff --git a/src/redis.js b/src/redis.js
index af962ac4a9..e2d5615421 100644
--- a/src/redis.js
+++ b/src/redis.js
@@ -1,7 +1,8 @@
(function(RedisDB) {
var redis = require('redis'),
nconf = require('nconf'),
- utils = require('./../public/src/utils.js');
+ utils = require('./../public/src/utils.js'),
+ winston = require('winston');
RedisDB.exports = redis.createClient(nconf.get('redis:port'), nconf.get('redis:host'));
@@ -11,14 +12,9 @@
RedisDB.exports.handle = function(error) {
if (error !== null) {
+ winston.err(error);
if (global.env !== 'production') {
- console.log("################# ERROR LOG ####################");
- console.log(error);
- console.log(arguments.callee.name);
- console.log("################# ERROR LOG ####################");
throw new Error(error);
- } else {
- console.log(error);
}
}
}
diff --git a/src/routes/admin.js b/src/routes/admin.js
index 75afd05c66..b14dde3dbc 100644
--- a/src/routes/admin.js
+++ b/src/routes/admin.js
@@ -4,7 +4,8 @@ var user = require('./../user.js'),
RDB = require('./../redis.js'),
pkg = require('./../../package.json'),
categories = require('./../categories.js'),
- plugins = require('../plugins');
+ plugins = require('../plugins'),
+ winston = require('winston');
(function(Admin) {
Admin.isAdmin = function(req, res, next) {
@@ -64,39 +65,30 @@ var user = require('./../user.js'),
});
app.get('/api/admin/users/search', function(req, res) {
- res.json({search_display: 'block', users: []});
+ res.json({search_display: 'block', loadmore_display:'none', users: []});
});
app.get('/api/admin/users/latest', function(req, res) {
- user.getUserList(function(data) {
- data = data.sort(function(a, b) {
- return b.joindate - a.joindate;
- });
- res.json({search_display: 'none', users:data, yourid:req.user.uid});
+ user.getUsers('users:joindate', 0, 49, function(err, data) {
+ res.json({ search_display: 'none', loadmore_display:'block', users:data, yourid:req.user.uid });
});
});
app.get('/api/admin/users/sort-posts', function(req, res) {
- user.getUserList(function(data) {
- data = data.sort(function(a, b) {
- return b.postcount - a.postcount;
- });
- res.json({search_display: 'none', users:data, yourid:req.user.uid});
+ user.getUsers('users:postcount', 0, 49, function(err, data) {
+ res.json({ search_display: 'none', loadmore_display:'block', users:data, yourid:req.user.uid });
});
});
app.get('/api/admin/users/sort-reputation', function(req, res) {
- user.getUserList(function(data) {
- data = data.sort(function(a, b) {
- return b.reputation - a.reputation;
- });
- res.json({search_display: 'none', users:data, yourid:req.user.uid});
+ user.getUsers('users:reputation', 0, 49, function(err, data) {
+ res.json({ search_display: 'none', loadmore_display:'block', users:data, yourid:req.user.uid });
});
});
app.get('/api/admin/users', function(req, res) {
- user.getUserList(function(data) {
- res.json({search_display: 'none', users:data, yourid:req.user.uid});
+ user.getUsers('users:joindate', 0, 49, function(err, data) {
+ res.json({ search_display: 'none', users:data, yourid:req.user.uid });
});
});
@@ -139,7 +131,10 @@ var user = require('./../user.js'),
for(var i in data) {
- try {
+ if(data[i].indexOf(':') == -1 || !data[i])
+ continue;
+
+ try {
data[i] = data[i].replace(/:/,"\":\"");
var json = "{\"" + data[i] + "\"}";
@@ -148,7 +143,7 @@ var user = require('./../user.js'),
finalData[key] = jsonObject[key];
}
} catch(err){
- console.log(err);
+ winston.warn('can\'t parse redis status variable, ignoring', i, data[i], err);
}
}
diff --git a/src/routes/api.js b/src/routes/api.js
index 87aca5b259..9900b51501 100644
--- a/src/routes/api.js
+++ b/src/routes/api.js
@@ -3,7 +3,8 @@ var user = require('./../user.js'),
topics = require('./../topics.js'),
categories = require('./../categories.js')
utils = require('./../../public/src/utils.js'),
- pkg = require('../../package.json');
+ pkg = require('../../package.json'),
+ meta = require('./../meta.js');
(function(Api) {
@@ -13,6 +14,19 @@ var user = require('./../user.js'),
res.json(data);
});
});
+
+ app.get('/api/config', function(req, res, next) {
+ meta.config.getFields(['postDelay', 'minimumTitleLength', 'minimumPostLength'], function(err, metaConfig) {
+ if(err) return next();
+ var clientConfig = require('../../public/config.json');
+
+ for (var attrname in metaConfig) {
+ clientConfig[attrname] = metaConfig[attrname];
+ }
+
+ res.json(200, clientConfig);
+ })
+ });
app.get('/api/home', function(req, res) {
var uid = (req.user) ? req.user.uid : 0;
@@ -187,7 +201,7 @@ var user = require('./../user.js'),
search(topicSearch, function(err, tids) {
if(err)
return callback(err, null);
- console.log(tids);
+
topics.getTopicsByTids(tids, 0, function(topics) {
callback(null, topics);
}, 0);
diff --git a/src/routes/authentication.js b/src/routes/authentication.js
index ecdf8972fe..60ce935557 100644
--- a/src/routes/authentication.js
+++ b/src/routes/authentication.js
@@ -6,7 +6,8 @@
passportFacebook = require('passport-facebook').Strategy,
login_strategies = [],
nconf = require('nconf'),
- users = require('../user'),
+ user = require('../user'),
+ winston = require('winston'),
login_module = require('./../login.js');
passport.use(new passportLocal(function(user, password, next) {
@@ -85,7 +86,7 @@
app.get('/logout', function(req, res) {
if (req.user && req.user.uid > 0) {
- console.log('info: [Auth] Session ' + req.sessionID + ' logout (uid: ' + req.user.uid + ')');
+ winston.info('[Auth] Session ' + req.sessionID + ' logout (uid: ' + req.user.uid + ')');
login_module.logout(req.sessionID, function(logout) {
req.logout();
app.build_header({ req: req, res: res }, function(err, header) {
@@ -132,20 +133,30 @@
app.get('/reset', function(req, res) {
app.build_header({ req: req, res: res }, function(err, header) {
- console.log(header);
res.send(header + templates['reset'] + templates['footer']);
});
});
-
-
- app.post('/login', passport.authenticate('local'), function(req, res) {
- res.json({success:1});
+
+ app.post('/login', function(req, res, next) {
+ passport.authenticate('local', function(err, user, info) {
+ if(err) {
+ return next(err);
+ }
+ if (!user) {
+ return res.send({ success : false, message : info.message });
+ }
+ req.login({
+ uid: user.uid
+ }, function() {
+ res.send({ success : true, message : 'authentication succeeded' });
+ });
+ })(req, res, next);
});
app.post('/register', function(req, res) {
- users.create(req.body.username, req.body.password, req.body.email, function(err, uid) {
+ user.create(req.body.username, req.body.password, req.body.email, function(err, uid) {
- if (err === null && uid > 0) {
+ if (err === null && uid) {
req.login({
uid: uid
}, function() {
diff --git a/src/routes/user.js b/src/routes/user.js
index 76d7e7586f..a164e8d8f5 100644
--- a/src/routes/user.js
+++ b/src/routes/user.js
@@ -4,7 +4,8 @@ var user = require('./../user.js'),
fs = require('fs'),
utils = require('./../../public/src/utils.js'),
path = require('path'),
- marked = require('marked');
+ marked = require('marked'),
+ winston = require('winston');
(function(User) {
User.create_routes = function(app) {
@@ -63,13 +64,13 @@ var user = require('./../user.js'),
user.get_uid_by_userslug(req.params.userslug, function(uid) {
if(!uid) {
- next();
- return;
+ return next();
}
-
+
app.build_header({ req: req, res: res }, function(err, header) {
- res.send(header + app.create_route('users/'+req.params.userslug, 'account') + templates['footer']);
- });
+ res.send(header + app.create_route('users/' + req.params.userslug, 'account') + templates['footer']);
+ });
+
});
});
@@ -136,7 +137,7 @@ var user = require('./../user.js'),
fs.unlink(absolutePath, function(err) {
if(err) {
- console.error('[%d] %s', Date.now(), + err);
+ winston.error('[%d] %s', Date.now(), + err);
}
uploadUserPicture(req.user.uid, path.extname(req.files.userPhoto.name), req.files.userPhoto.path, res);
@@ -155,8 +156,7 @@ var user = require('./../user.js'),
var filename = uid + '-profileimg' + extension;
var uploadPath = path.join(global.configuration['ROOT_DIRECTORY'], global.nconf.get('upload_path'), filename);
- // @todo move to proper logging code - this should only be temporary
- console.log('Info: Attempting upload to: '+ uploadPath);
+ winston.info('Attempting upload to: '+ uploadPath);
var is = fs.createReadStream(tempPath);
var os = fs.createWriteStream(uploadPath);
@@ -176,11 +176,7 @@ var user = require('./../user.js'),
height: 128
}, function(err, stdout, stderr){
if (err) {
- // @todo: better logging method; for now, send to stderr.
- // ideally, this should be happening in another process
- // to avoid poisoning the main process on error or allowing a significant problem
- // to crash the main process
- console.error('[%d] %s', Date.now(), + err);
+ winston.err(err.message, err.stack);
}
res.json({ path: imageUrl });
@@ -189,7 +185,7 @@ var user = require('./../user.js'),
});
os.on('error', function(err) {
- console.error('[%d] %s', Date.now(), + err);
+ winston.error('[%d] %s', Date.now(), + err);
});
is.pipe(os);
@@ -316,49 +312,33 @@ var user = require('./../user.js'),
});
});
- app.get('/api/users', function(req, res) {
- user.getUserList(function(data) {
- data = data.sort(function(a, b) {
- return b.joindate - a.joindate;
- });
- res.json({ search_display: 'none', users: data });
- });
- });
-
+ app.get('/api/users', getUsersSortedByJoinDate);
app.get('/api/users-sort-posts', getUsersSortedByPosts);
app.get('/api/users-sort-reputation', getUsersSortedByReputation);
app.get('/api/users-latest', getUsersSortedByJoinDate);
app.get('/api/users-search', getUsersForSearch);
- function getUsersSortedByPosts(req, res) {
- user.getUserList(function(data) {
- data = data.sort(function(a, b) {
- return b.postcount - a.postcount;
- });
- res.json({ search_display: 'none', users:data });
+
+ function getUsersSortedByJoinDate(req, res) {
+ user.getUsers('users:joindate', 0, 49, function(err, data) {
+ res.json({ search_display: 'none', loadmore_display:'block', users:data });
});
}
-
- function getUsersSortedByReputation(req, res) {
- user.getUserList(function(data) {
- data = data.sort(function(a, b) {
- return b.reputation - a.reputation;
- });
- res.json({ search_display: 'none', users:data });
+
+ function getUsersSortedByPosts(req, res) {
+ user.getUsers('users:postcount', 0, 49, function(err, data) {
+ res.json({ search_display: 'none', loadmore_display:'block', users:data });
});
}
- function getUsersSortedByJoinDate(req, res) {
- user.getUserList(function(data) {
- data = data.sort(function(a, b) {
- return b.joindate - a.joindate;
- });
- res.json({ search_display: 'none', users:data });
+ function getUsersSortedByReputation(req, res) {
+ user.getUsers('users:reputation', 0, 49, function(err, data) {
+ res.json({ search_display: 'none', loadmore_display:'block', users:data });
});
}
function getUsersForSearch(req, res) {
- res.json({ search_display: 'block', users: [] });
+ res.json({ search_display: 'block', loadmore_display:'none', users: [] });
}
function getUserDataByUserSlug(userslug, callerUID, callback) {
@@ -391,7 +371,8 @@ var user = require('./../user.js'),
else
data.emailClass = "hide";
-
+ data.show_banned = data.banned === '1'?'':'hide';
+
data.uid = uid;
data.yourid = callerUID;
data.theirid = uid;
diff --git a/src/threadTools.js b/src/threadTools.js
index 5cc4979104..4e9efe9311 100644
--- a/src/threadTools.js
+++ b/src/threadTools.js
@@ -6,7 +6,8 @@ var RDB = require('./redis.js'),
notifications = require('./notifications.js'),
posts = require('./posts'),
reds = require('reds'),
- topicSearch = reds.createSearch('nodebbtopicsearch');
+ topicSearch = reds.createSearch('nodebbtopicsearch'),
+ winston = require('winston');
(function(ThreadTools) {
@@ -192,7 +193,7 @@ var RDB = require('./redis.js'),
categories.moveRecentReplies(tid, oldCid, cid, function(err, data) {
if(err) {
- console.log(err);
+ winston.err(err);
}
});
@@ -289,7 +290,7 @@ 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);
@@ -297,8 +298,7 @@ var RDB = require('./redis.js'),
}
}
- // If we got here, nothing was found...
callback(new Error('no-undeleted-pids-found'));
- });
+ });
}
}(exports));
\ No newline at end of file
diff --git a/src/topics.js b/src/topics.js
index c5301bc653..fff4ee3ae4 100644
--- a/src/topics.js
+++ b/src/topics.js
@@ -20,7 +20,7 @@ marked.setOptions({
(function(Topics) {
- Topics.minimumTitleLength = 3;
+
Topics.getTopicData = function(tid, callback) {
RDB.hgetall('topic:' + tid, function(err, data) {
@@ -81,6 +81,7 @@ marked.setOptions({
for(var i=0; i
.+\n\n/, '');
+ stripped = utils.strip_tags(postTools.markdownToHTML(stripped));
+ }
+
callback(null, {
"text": stripped,
"username": userData.username,
@@ -528,7 +531,7 @@ marked.setOptions({
type: 'error',
timeout: 2000,
title: 'Title too short',
- message: "Please enter a longer title. At least " + Topics.minimumTitleLength + " characters.",
+ message: "Please enter a longer title. At least " + config.minimumTitleLength + " characters.",
alert_id: 'post_error'
});
}
@@ -545,17 +548,17 @@ marked.setOptions({
if (uid === 0) {
callback(new Error('not-logged-in'), null);
return;
- } else if(!title || title.length < Topics.minimumTitleLength) {
+ } else if(!title || title.length < config.minimumTitleLength) {
callback(new Error('title-too-short'), null);
return;
- } else if (!content || content.length < posts.miminumPostLength) {
+ } else if (!content || content.length < config.miminumPostLength) {
callback(new Error('content-too-short'), null);
return;
}
user.getUserField(uid, 'lastposttime', function(lastposttime) {
- if(Date.now() - lastposttime < config.post_delay) {
+ if(Date.now() - lastposttime < config.postDelay) {
callback(new Error('too-many-posts'), null);
return;
}
diff --git a/src/upgrade.js b/src/upgrade.js
index 7bf8b1abc5..1b6dc494c7 100644
--- a/src/upgrade.js
+++ b/src/upgrade.js
@@ -1,6 +1,6 @@
var RDB = require('./redis.js'),
- async = require('async');
-
+ async = require('async'),
+ winston = require('winston');
function upgradeCategory(cid, callback) {
@@ -20,7 +20,6 @@ function upgradeCategory(cid, callback) {
async.each(tids, moveTopic, function(err) {
if(!err) {
- console.log('renaming ' + cid);
RDB.rename('temp_categories:' + cid + ':tid', 'categories:' + cid + ':tid');
callback(null);
}
@@ -30,43 +29,70 @@ function upgradeCategory(cid, callback) {
});
} else {
- console.log('category already upgraded '+ cid);
+ winston.info('category already upgraded '+ cid);
callback(null);
}
});
}
+function upgradeUser(uid, callback) {
+ RDB.hmgetObject('user:' + uid, ['joindate', 'postcount', 'reputation'], function(err, userData) {
+ if(err)
+ return callback(err);
+
+ RDB.zadd('users:joindate', userData.joindate, uid);
+ RDB.zadd('users:postcount', userData.postcount, uid);
+ RDB.zadd('users:reputation', userData.reputation, uid);
+
+ callback(null);
+ });
+
+}
exports.upgrade = function() {
- console.log('upgrading nodebb now');
+ winston.info('upgrading nodebb now');
var schema = [
function upgradeCategories(next) {
- console.log('upgrading categories');
+ winston.info('upgrading categories');
RDB.lrange('categories:cid', 0, -1, function(err, cids) {
async.each(cids, upgradeCategory, function(err) {
- if(!err)
- next(null, 'upgraded categories');
- else
+ if(!err) {
+ winston.info('upgraded categories');
+ next(null, null);
+ } else {
next(err, null);
+ }
});
});
},
function upgradeUsers(next) {
- console.log('upgrading users');
- next(null, 'upgraded users');
+ winston.info('upgrading users');
+
+ RDB.lrange('userlist', 0, -1, function(err, uids) {
+
+ async.each(uids, upgradeUser, function(err) {
+ if(!err) {
+ winston.info('upgraded users')
+ next(null, null);
+ } else {
+ next(err, null);
+ }
+ });
+
+ });
}
];
async.series(schema, function(err, results) {
if(!err)
- console.log('upgrade complete');
+ winston.info('upgrade complete');
else
- console.log(err);
+ winston.err(err);
process.exit();
diff --git a/src/user.js b/src/user.js
index 608115595c..b6e9e943f5 100644
--- a/src/user.js
+++ b/src/user.js
@@ -41,13 +41,14 @@ var utils = require('./../public/src/utils.js'),
} else next();
}
], function(err, results) {
- if (err) return callback(err, 0); // FIXME: Maintaining the 0 for backwards compatibility. Do we need this?
+ if (err) return callback(err, null);
RDB.incr('global:next_user_id', function(err, uid) {
RDB.handle(err);
var gravatar = User.createGravatarURLFromEmail(email);
-
+ var timestamp = Date.now();
+
RDB.hmset('user:'+uid, {
'uid': uid,
'username' : username,
@@ -58,7 +59,7 @@ var utils = require('./../public/src/utils.js'),
'website':'',
'email' : email || '',
'signature':'',
- 'joindate' : Date.now(),
+ 'joindate' : timestamp,
'picture': gravatar,
'gravatarpicture' : gravatar,
'uploadedpicture': '',
@@ -66,6 +67,7 @@ var utils = require('./../public/src/utils.js'),
'postcount': 0,
'lastposttime': 0,
'administrator': (uid == 1) ? 1 : 0,
+ 'banned': 0,
'showemail': 0
});
@@ -83,7 +85,9 @@ var utils = require('./../public/src/utils.js'),
io.sockets.emit('user.count', {count: count});
});
- RDB.lpush('userlist', uid);
+ RDB.zadd('users:joindate', timestamp, uid);
+ RDB.zadd('users:postcount', 0, uid);
+ RDB.zadd('users:reputation', 0, uid);
io.sockets.emit('user.latest', {userslug: userslug, username: username});
@@ -112,7 +116,9 @@ var utils = require('./../public/src/utils.js'),
RDB.del('followers:' + uid);
RDB.del('following:' + uid);
- RDB.lrem('userlist', 1, uid);
+ RDB.zrem('users:joindate', uid);
+ RDB.zrem('users:postcount', uid);
+ RDB.zrem('users:reputation', uid);
callback(true);
});
@@ -121,6 +127,14 @@ var utils = require('./../public/src/utils.js'),
}
});
}
+
+ User.ban = function(uid, callback) {
+ User.setUserField(uid, 'banned', 1, callback);
+ }
+
+ User.unban = function(uid, callback) {
+ User.setUserField(uid, 'banned', 0, callback);
+ }
User.getUserField = function(uid, field, callback) {
RDB.hget('user:' + uid, field, function(err, data) {
@@ -185,6 +199,12 @@ var utils = require('./../public/src/utils.js'),
});
}
+ User.filterBannedUsers = function(users) {
+ return users.filter(function(user) {
+ return (!user.banned || user.banned === '0');
+ });
+ }
+
User.updateProfile = function(uid, data, callback) {
var fields = ['email', 'fullname', 'website', 'location', 'birthday', 'signature'];
@@ -304,28 +324,29 @@ var utils = require('./../public/src/utils.js'),
});
}
- User.setUserField = function(uid, field, value) {
- RDB.hset('user:' + uid, field, value);
+ User.setUserField = function(uid, field, value, callback) {
+ RDB.hset('user:' + uid, field, value, callback);
}
User.setUserFields = function(uid, data) {
RDB.hmset('user:' + uid, data);
}
- User.incrementUserFieldBy = function(uid, field, value) {
- RDB.hincrby('user:' + uid, field, value);
+ User.incrementUserFieldBy = function(uid, field, value, callback) {
+ RDB.hincrby('user:' + uid, field, value, callback);
}
- User.decrementUserFieldBy = function(uid, field, value) {
- RDB.hincrby('user:' + uid, field, -value);
+ User.decrementUserFieldBy = function(uid, field, value, callback) {
+ RDB.hincrby('user:' + uid, field, -value, callback);
}
- User.getUserList = function(callback) {
+ User.getUsers = function(set, start, stop, callback) {
var data = [];
-
- RDB.lrange('userlist', 0, -1, function(err, uids) {
-
- RDB.handle(err);
+
+ RDB.zrevrange(set, start, stop, function(err, uids) {
+ if(err) {
+ return callback(err, null);
+ }
function iterator(uid, callback) {
User.getUserData(uid, function(userData) {
@@ -336,13 +357,8 @@ var utils = require('./../public/src/utils.js'),
});
}
- async.each(uids, iterator, function(err) {
- if(!err) {
- callback(data);
- } else {
- console.log(err);
- callback(null);
- }
+ async.eachSeries(uids, iterator, function(err) {
+ callback(err, data);
});
});
}
@@ -401,7 +417,10 @@ var utils = require('./../public/src/utils.js'),
User.onNewPostMade = function(uid, tid, pid, timestamp) {
User.addPostIdToUser(uid, pid);
- User.incrementUserFieldBy(uid, 'postcount', 1);
+ User.incrementUserFieldBy(uid, 'postcount', 1, function(err, newpostcount) {
+ RDB.zadd('users:postcount', newpostcount, uid);
+ });
+
User.setUserField(uid, 'lastposttime', timestamp);
User.sendPostNotificationToFollowers(uid, tid, pid);
@@ -602,7 +621,7 @@ var utils = require('./../public/src/utils.js'),
};
User.latest = function(socket) {
- RDB.lrange('userlist', 0, 0, function(err, uid) {
+ RDB.zrevrange('users:joindate', 0, 0, function(err, uid) {
RDB.handle(err);
User.getUserFields(uid, ['username', 'userslug'], function(userData) {
diff --git a/src/webserver.js b/src/webserver.js
index 243b7885e0..6d8d47afea 100644
--- a/src/webserver.js
+++ b/src/webserver.js
@@ -108,7 +108,6 @@ var express = require('express'),
// respond with html page
if (req.accepts('html')) {
-
//res.json('404', { url: req.url });
res.redirect(global.nconf.get('relative_path') + '/404');
return;
@@ -116,7 +115,6 @@ var express = require('express'),
// respond with json
if (req.accepts('json')) {
- console.log('sending 404 json');
res.send({ error: 'Not found' });
return;
}
@@ -126,6 +124,7 @@ var express = require('express'),
});
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().
@@ -401,6 +400,7 @@ var express = require('express'),
}
});
});
+
});
}(WebServer));
diff --git a/src/websockets.js b/src/websockets.js
index 6fa6c2568f..1003e45a06 100644
--- a/src/websockets.js
+++ b/src/websockets.js
@@ -26,7 +26,8 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
'categories': require('./admin/categories.js'),
'user': require('./admin/user.js')
},
- plugins = require('./plugins');
+ plugins = require('./plugins'),
+ winston = require('winston');
(function(io) {
var users = {},
@@ -366,7 +367,7 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
if(err) {
if(err.message === 'content-too-short') {
posts.emitContentTooShortAlert(socket);
- } else if(err.messages === 'too-many-posts') {
+ } else if(err.message === 'too-many-posts') {
posts.emitTooManyPostsAlert(socket);
} else if(err.message === 'reply-error') {
socket.emit('event:alert', {
@@ -462,7 +463,7 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
if(!data.title || data.title.length < topics.minimumTitleLength) {
topics.emitTitleTooShortAlert(socket);
return;
- } else if (!data.content || data.content.length < posts.minimumPostLength) {
+ } else if (!data.content || data.content.length < require('../public/config.json').minimumPostLength) {
posts.emitContentTooShortAlert(socket);
return;
}
@@ -657,12 +658,24 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
var start = data.after,
end = start + 9;
- console.log(start, end);
topics.getUnreadTopics(uid, start, end, function(unreadTopics) {
callback(unreadTopics);
});
});
+ 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) {
topics.getAllTopics(data.limit, data.after, function(topics) {
callback(JSON.stringify(topics));
@@ -691,14 +704,26 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
}
});
+ socket.on('api:admin.user.banUser', function(theirid) {
+ if(uid && uid > 0) {
+ admin.user.banUser(uid, theirid, socket);
+ }
+ });
+
+ socket.on('api:admin.user.unbanUser', function(theirid) {
+ if(uid && uid > 0) {
+ admin.user.unbanUser(uid, theirid, socket);
+ }
+ });
+
socket.on('api:admin.user.search', function(username) {
if(uid && uid > 0) {
user.search(username, function(data) {
socket.emit('api:admin.user.search', data);
});
- }
- else
+ } else {
socket.emit('api:admin.user.search', null);
+ }
});
socket.on('api:admin.themes.getInstalled', function(callback) {