merging master to pull baris' latest fixes

v1.18.x
psychobunny 12 years ago
commit df15dceaef

@ -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,28 +50,22 @@ 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'),
RDB = require('./src/redis.js'),
templates = require('./public/src/templates.js'),
webserver = require('./src/webserver.js'),
websockets = require('./src/websockets.js'),
@ -80,6 +75,7 @@ if(nconf.get('upgrade')) {
};
DEVELOPMENT = true;
RDB = require('./src/redis.js');
global.configuration = {};
global.templates = {};
@ -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();
});
}

@ -34,7 +34,8 @@
"cheerio": "~0.12.0",
"request": "~2.25.0",
"reds": "~0.2.4",
"winston": "~0.7.2"
"winston": "~0.7.2",
"nodebb-plugin-mentions": "~0.1.0"
},
"bugs": {
"url": "https://github.com/designcreateplay/NodeBB/issues"

@ -245,6 +245,7 @@ footer.footer {
color: #333;
margin-bottom: 10px;
cursor: pointer;
overflow:hidden;
p {
color: #333;
}

@ -2,7 +2,7 @@ var ajaxify = {};
(function($) {
var location = document.location || window.location,
rootUrl = location.protocol + '//' + (location.hostname || location.host) + (location.port ? ':' + location.port : ''),
content = null;
@ -39,14 +39,14 @@ var ajaxify = {};
}
var tpl_url = templates.get_custom_map(url.split('?')[0]);
if (tpl_url == false && !templates[url]) {
if(url === '' || url === '/') {
tpl_url = 'home';
} else {
tpl_url = url.split('/')[0].split('?')[0];
}
} else if (templates[url]) {
tpl_url = url;
}
@ -67,9 +67,9 @@ var ajaxify = {};
if (callback) {
callback();
}
app.process_page();
jQuery('#content, #footer').stop(true, true).fadeIn(200, function() {
if(window.location.hash)
hash = window.location.hash;
@ -77,9 +77,9 @@ var ajaxify = {};
app.scrollToPost(hash.substr(1));
});
}, url, template);
utils.refreshTitle(url);
utils.refreshTitle(url);
}, url, template);
return true;
}
@ -94,12 +94,15 @@ var ajaxify = {};
// Enhancing all anchors to ajaxify...
$(document.body).on('click', 'a', function(e) {
if (this.href == window.location.href + "#") return;
if(this.href.slice(-1) === "#") return;
function hrefEmpty(href) {
return href == 'javascript:;' || href == window.location.href + "#" || href.slice(-1) === "#";
}
if(hrefEmpty(this.href)) return;
var url = this.href.replace(rootUrl +'/', '');
if (this.target !== '') return;
if (!e.ctrlKey && e.which === 1) {
@ -126,7 +129,7 @@ var ajaxify = {};
script.type = "text/javascript";
try {
script.appendChild(document.createTextNode(data));
script.appendChild(document.createTextNode(data));
} catch(e) {
script.text = data;
}
@ -162,5 +165,5 @@ var ajaxify = {};
evalScript(scripts[i]);
}
};
}(jQuery));

@ -218,7 +218,6 @@ var socket,
app.current_room = null;
app.enter_room = function(room) {
if(socket) {
if (app.current_room === room)
return;
@ -333,28 +332,47 @@ var socket,
app.infiniteLoaderActive = false;
if(data.posts.length) {
app.createNewPosts(data);
if(callback)
callback();
}
if(callback)
callback(data.posts);
});
}
app.scrollToPost = function(pid) {
if(!pid)
return;
var container = $(document.body),
scrollTo = $('#post_anchor_' + pid),
tid = $('#post-container').attr('data-tid');
while(!scrollTo.length) {
app.loadMorePosts(tid, function() {
scrollTo = $('#post_anchor_' + pid);
function animateScroll() {
$('body,html').animate({
scrollTop: scrollTo.offset().top - container.offset().top + container.scrollTop() - $('#header-menu').height()
});
}
container.animate({
scrollTop: scrollTo.offset().top - container.offset().top + container.scrollTop() - $('#header-menu').height()
});
if(!scrollTo.length && tid) {
var intervalID = setInterval(function() {
app.loadMorePosts(tid, function(posts) {
scrollTo = $('#post_anchor_' + pid);
if(tid && scrollTo.length) {
animateScroll();
}
if(!posts.length || scrollTo.length)
clearInterval(intervalID);
});
}, 100);
} else if(tid) {
animateScroll();
}
}
jQuery('document').ready(function() {

@ -9,12 +9,12 @@
pinned: templates.get('pinned')
},
topic_name = templates.get('topic_name');
jQuery('document').ready(function() {
app.addCommasToNumbers();
var room = 'topic_' + tid,
adminTools = document.getElementById('thread-tools');
@ -26,17 +26,12 @@
if (thread_state.pinned === '1') set_pinned_state(true);
if (expose_tools === '1') {
var deleteThreadEl = document.getElementById('delete_thread'),
lockThreadEl = document.getElementById('lock_thread'),
pinThreadEl = document.getElementById('pin_thread'),
moveThreadEl = document.getElementById('move_thread'),
moveThreadModal = $('#move_thread_modal');
var moveThreadModal = $('#move_thread_modal');
adminTools.style.visibility = 'inherit';
// Add events to the thread tools
deleteThreadEl.addEventListener('click', function(e) {
e.preventDefault();
$('#delete_thread').on('click', function(e) {
if (thread_state.deleted !== '1') {
bootbox.confirm('Are you sure you want to delete this thread?', function(confirm) {
if (confirm) socket.emit('api:topic.delete', { tid: tid });
@ -46,30 +41,31 @@
if (confirm) socket.emit('api:topic.restore', { tid: tid });
});
}
}, false);
return false;
});
lockThreadEl.addEventListener('click', function(e) {
e.preventDefault();
$('#lock_thread').on('click', function(e) {
if (thread_state.locked !== '1') {
socket.emit('api:topic.lock', { tid: tid });
} else {
socket.emit('api:topic.unlock', { tid: tid });
}
}, false);
return false;
});
pinThreadEl.addEventListener('click', function(e) {
e.preventDefault();
$('#pin_thread').on('click', function(e) {
if (thread_state.pinned !== '1') {
socket.emit('api:topic.pin', { tid: tid });
} else {
socket.emit('api:topic.unpin', { tid: tid });
}
}, false);
return false;
});
moveThreadEl.addEventListener('click', function(e) {
e.preventDefault();
$('#move_thread').on('click', function(e) {
moveThreadModal.modal('show');
}, false);
return false;
});
moveThreadModal.on('shown', function() {
var loadingEl = document.getElementById('categories-loading');
@ -195,7 +191,7 @@
});
}
});
socket.emit('api:topic.followCheck', tid);
if(followEl[0]) {
followEl[0].addEventListener('click', function() {
@ -284,7 +280,7 @@
socket.emit('api:posts.delete', { pid: pid }) :
socket.emit('api:posts.restore', { pid: pid });
}
});
});
$('.post-container').delegate('.chat', 'click', function(e) {
@ -296,7 +292,7 @@
chatModal.show();
chat.bringModalToTop(chatModal);
});
});
ajaxify.register_events([
@ -372,7 +368,7 @@
var editedPostEl = document.getElementById('content_' + data.pid);
var editedPostTitle = $('#topic_title_'+data.pid);
if(editedPostTitle.length > 0) {
editedPostTitle.fadeOut(250, function() {
editedPostTitle.html(data.title);
@ -402,7 +398,7 @@
if (favEl) {
favEl.className = 'icon-star-empty';
$(favEl).parent().removeClass('btn-warning');
}
}
}
});
@ -595,7 +591,7 @@
var postEl = $(document.querySelector('#post-container li[data-pid="' + pid + '"]')),
editEl = postEl.find('.edit'),
deleteEl = postEl.find('.delete');
if (state) {
editEl.removeClass('none');
deleteEl.removeClass('none');

@ -153,6 +153,11 @@
.addClass('badge-inverse')
}
});
},
isRelativeUrl: function(url) {
var firstChar = url.slice(0, 1);
return (firstChar === '.' || firstChar === '/');
}
}

@ -27,6 +27,8 @@
</script>
<link rel="stylesheet" type="text/css" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css">
<script type="text/javascript" src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<script src="{relative_path}/src/utils.js"></script>
<link rel="stylesheet" type="text/css" href="{relative_path}/css/style.css" />
<link rel="stylesheet" type="text/css" href="{relative_path}/css/admin.css" />
</head>

@ -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);
});

@ -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",

@ -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));
}(exports));

@ -20,28 +20,14 @@ var fs = require('fs'),
function(plugins, next) {
async.each(plugins, function(plugin) {
// TODO: Update this check to also check node_modules
var pluginPath = path.join(__dirname, '../plugins/', plugin);
fs.exists(pluginPath, function(exists) {
if (exists) {
fs.readFile(path.join(pluginPath, 'plugin.json'), function(err, data) {
if (err) return next(err);
var pluginData = JSON.parse(data);
_self.libraries[pluginData.id] = require(path.join(pluginPath, pluginData.library));
if (pluginData.hooks) {
for(var x=0,numHooks=pluginData.hooks.length;x<numHooks;x++) {
_self.registerHook(pluginData.id, pluginData.hooks[x]);
}
}
if (global.env === 'development') winston.info('[plugins] Loaded plugin: ' + pluginData.id);
next();
});
} else {
if (global.env === 'development') winston.info('[plugins] Plugin \'' + plugin + '\' not found');
next(); // Ignore this plugin silently
}
})
var pluginPath = path.join(__dirname, '../plugins/', plugin),
modulePath = path.join(__dirname, '../node_modules/', plugin);
if (fs.existsSync(pluginPath)) _self.loadPlugin(pluginPath, next);
else if (fs.existsSync(modulePath)) _self.loadPlugin(modulePath, next);
else {
if (global.env === 'development') winston.info('[plugins] Plugin \'' + plugin + '\' not found');
next(); // Ignore this plugin silently
}
}, next);
}
], function(err) {
@ -54,6 +40,24 @@ var fs = require('fs'),
});
},
initialized: false,
loadPlugin: function(pluginPath, callback) {
var _self = this;
fs.readFile(path.join(pluginPath, 'plugin.json'), function(err, data) {
if (err) return callback(err);
var pluginData = JSON.parse(data);
_self.libraries[pluginData.id] = require(path.join(pluginPath, pluginData.library));
if (pluginData.hooks) {
for(var x=0,numHooks=pluginData.hooks.length;x<numHooks;x++) {
_self.registerHook(pluginData.id, pluginData.hooks[x]);
}
}
if (global.env === 'development') winston.info('[plugins] Loaded plugin: ' + pluginData.id);
callback();
});
},
registerHook: function(id, data) {
/*
`data` is an object consisting of (* is required):
@ -66,7 +70,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]);
_self.loadedHooks[data.hook].push([id, data.method, !!data.callbacked]);
if (global.env === 'development') winston.info('[plugins] Hook registered: ' + data.hook + ' will call ' + id);
} else return;
},
@ -84,7 +88,7 @@ var fs = require('fs'),
var returnVal = (Array.isArray(args) ? args[0] : args);
async.each(hookList, function(hookObj, next) {
if (hookObj.callbacked) {
if (hookObj[2]) {
_self.libraries[hookObj[0]][hookObj[1]](returnVal, function(err, afterVal) {
returnVal = afterVal;
next(err);
@ -95,7 +99,9 @@ var fs = require('fs'),
}
}, function(err) {
if (err) {
if (global.env === 'development') winston.info('[plugins] Problem executing hook: ' + hook);
if (global.env === 'development') {
winston.info('[plugins] Problem executing hook: ' + hook);
}
}
callback(returnVal);
@ -150,26 +156,49 @@ var fs = require('fs'),
showInstalled: function(callback) {
// TODO: Also check /node_modules
var _self = this;
moduleBasePath = path.join(__dirname, '../plugins');
localPluginPath = path.join(__dirname, '../plugins'),
npmPluginPath = path.join(__dirname, '../node_modules');
async.waterfall([
function(next) {
fs.readdir(moduleBasePath, next);
async.parallel([
function(next) {
fs.readdir(localPluginPath, next);
},
function(next) {
fs.readdir(npmPluginPath, next);
}
], function(err, dirs) {
if (err) return next(err);
dirs[0] = dirs[0].map(function(file) {
return path.join(localPluginPath, file);
}).filter(function(file) {
var stats = fs.statSync(file);
if (stats.isDirectory()) return true;
else return false;
});
dirs[1] = dirs[1].map(function(file) {
return path.join(npmPluginPath, file);
}).filter(function(file) {
var stats = fs.statSync(file);
if (stats.isDirectory() && file.substr(npmPluginPath.length+1, 14) === 'nodebb-plugin-') return true;
else return false;
});
next(err, dirs[0].concat(dirs[1]));
});
},
function(files, next) {
var plugins = [];
async.each(files, function(file, next) {
var modulePath = path.join(moduleBasePath, file),
configPath;
var configPath;
async.waterfall([
function(next) {
fs.stat(path.join(moduleBasePath, file), next);
},
function(stats, next) {
if (stats.isDirectory()) fs.readFile(path.join(modulePath, 'plugin.json'), next);
else next(new Error('not-a-directory'));
fs.readFile(path.join(file, 'plugin.json'), next);
},
function(configJSON, next) {
var config = JSON.parse(configJSON);

@ -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,17 +171,17 @@ 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');
if (href && !href.match(domain)) {
if (href && !href.match(domain) && !utils.isRelativeUrl(href)) {
this.attr('href', domain + 'outgoing?url=' + encodeURIComponent(href));
if (!isSignature) this.append(' <i class="icon-external-link"></i>');
}
});
html = parsedContentDOM.html();
} else {

@ -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();
@ -97,7 +102,10 @@ var RDB = require('./redis.js'),
Posts.getPostData = function(pid, callback) {
RDB.hgetall('post:' + pid, function(err, data) {
if(err === null) {
callback(data);
plugins.fireHook('filter:post.get', data.content, function(content) {
data.content = content;
callback(data);
});
}
else
console.log(err);
@ -143,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 = [];
}
@ -181,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'
});
}
@ -189,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
});
@ -200,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;
}
@ -224,22 +237,8 @@ var RDB = require('./redis.js'),
threadTools.notify_followers(tid, uid);
postData.content = postTools.markdownToHTML(postData.content);
postData.post_rep = 0;
postData.relativeTime = utils.relativeTime(postData.timestamp);
postData.fav_button_class = '';
postData.fav_star_class = 'icon-star-empty';
postData['edited-class'] = 'none';
postData.show_banned = 'hide';
postData.uploadedImages = JSON.parse(postData.uploadedImages);
var socketData = {
'posts' : [
postData
]
};
posts.addUserInfoToPost(socketData['posts'][0], function() {
Posts.addUserInfoToPost(postData, function() {
var socketData = { posts: [postData] };
io.sockets.in('topic_' + tid).emit('event:new_post', socketData);
io.sockets.in('recent_posts').emit('event:new_post', socketData);
});
@ -263,7 +262,7 @@ var RDB = require('./redis.js'),
RDB.incr('global:next_post_id', function(err, pid) {
RDB.handle(err);
plugins.fireHook('filter:save_post_content', content, function(content) {
plugins.fireHook('filter:post.save', content, function(content) {
var timestamp = Date.now(),
postData = {
'pid': pid,
@ -275,7 +274,14 @@ var RDB = require('./redis.js'),
'editor': '',
'edited': 0,
'deleted': 0,
'uploadedImages': ''
'uploadedImages': '[]',
'fav_button_class': '',
'fav_star_class': 'icon-star-empty',
'show_banned': 'hide',
'relativeTime': '0 seconds',
'post_rep': '0',
'edited-class': 'none',
'relativeEditTime': ''
};
RDB.hmset('post:' + pid, postData);
@ -306,17 +312,30 @@ var RDB = require('./redis.js'),
user.onNewPostMade(uid, tid, pid, timestamp);
uploadPostImages(postData, images, function(err, uploadedImages) {
if(err) {
winston.error('Uploading images failed!', err.stack);
} else {
postData.uploadedImages = JSON.stringify(uploadedImages);
Posts.setPostField(pid, 'uploadedImages', postData.uploadedImages);
async.parallel({
uploadedImages: function(next) {
uploadPostImages(postData, images, function(err, uploadedImages) {
if(err) {
winston.error('Uploading images failed!', err.stack);
next(null, []);
} else {
next(null, uploadedImages);
}
});
},
content: function(next) {
plugins.fireHook('filter:post.get', content, function(content) {
next(null, content);
});
}
}, function(err, results) {
postData.uploadedImages = results.uploadedImages;
Posts.setPostField(pid, 'uploadedImages', JSON.stringify(postData.uploadedImages));
postData.content = results.content;
callback(postData);
});
plugins.fireHook('action:save_post_content', [pid, content]);
plugins.fireHook('action:post.save', [pid, content]);
postSearch.index(content, pid);
});
@ -329,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 = [];

@ -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,9 @@ 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 <span>v " + pkg.version + "</span>\nWelcome to NodeBB, the discussion platform of the future.\n\n<div class='btn-group'><a target=\"_blank\" href=\"http://www.nodebb.org\" class=\"btn btn-default btn-lg\"><i class=\"icon-comment\"></i><span><span>&nbsp;Get NodeBB</span></span></a> <a target=\"_blank\" href=\"https://github.com/designcreateplay/NodeBB\" class=\"btn btn-default btn-lg\"><i class=\"icon-github-alt\"></i><span>&nbsp;Fork us on Github</span></a> <a target=\"_blank\" href=\"https://twitter.com/dcplabs\" class=\"btn btn-default btn-lg\"><i class=\"icon-twitter\"></i><span>&nbsp;@dcplabs</span></a></div>");
data.motd_class = (meta.config.show_motd === '1' || meta.config.show_motd === undefined) ? '' : 'none';
data.motd = marked(meta.config.motd || "# NodeBB <span>v " + pkg.version + "</span>\nWelcome to NodeBB, the discussion platform of the future.\n\n<div class='btn-group'><a target=\"_blank\" href=\"http://www.nodebb.org\" class=\"btn btn-default btn-lg\"><i class=\"icon-comment\"></i><span><span>&nbsp;Get NodeBB</span></span></a> <a target=\"_blank\" href=\"https://github.com/designcreateplay/NodeBB\" class=\"btn btn-default btn-lg\"><i class=\"icon-github-alt\"></i><span>&nbsp;Fork us on Github</span></a> <a target=\"_blank\" href=\"https://twitter.com/dcplabs\" class=\"btn btn-default btn-lg\"><i class=\"icon-twitter\"></i><span>&nbsp;@dcplabs</span></a></div>");
res.json(data);
});

@ -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) {

@ -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)

@ -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'));
});
}

@ -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<postData.length; ++i)
for(var i=0; i<postData.length; ++i)
pids.push(postData[i].pid);
favourites.getFavouritesByPostIDs(pids, current_user, function(fav_data) {
next(null, fav_data);
});
next(null, fav_data);
});
}
function addUserInfoToPosts(next) {
@ -63,16 +63,16 @@ marked.setOptions({
});
}
async.each(postData, iterator, function(err) {
async.each(postData, iterator, function(err) {
next(err, null);
});
}
}
function getPrivileges(next) {
threadTools.privileges(tid, current_user, function(privData) {
next(null, privData);
});
}
}
async.parallel([getFavouritesData, addUserInfoToPosts, getPrivileges], function(err, results) {
var fav_data = results[0],
@ -84,7 +84,7 @@ marked.setOptions({
postData[i]['display_moderator_tools'] = (postData[i].uid == current_user || privileges.editable) ? 'show' : 'none';
postData[i].show_banned = postData[i].user_banned === '1'?'show':'hide';
}
callback(postData);
});
});
@ -101,9 +101,9 @@ marked.setOptions({
var timestamp = Date.now();
var args = [ 'topics:recent', '+inf', timestamp - 86400000, 'WITHSCORES', 'LIMIT', start, end - start + 1];
RDB.zrevrangebyscore(args, function(err, tids) {
var latestTopics = {
'category_name' : 'Recent',
'show_sidebar' : 'hidden',
@ -126,18 +126,18 @@ marked.setOptions({
});
});
}
Topics.getTotalUnread = function(uid, callback) {
RDB.zrevrange('topics:recent', 0, 21, function (err, tids) {
Topics.hasReadTopics(tids, uid, function(read) {
var unreadTids = tids.filter(function(tid, index, self) {
return read[index] === 0;
});
});
callback({
count: unreadTids.length
});
});
});
});
};
@ -154,13 +154,13 @@ marked.setOptions({
};
RDB.zrevrange('topics:recent', start, stop, function (err, tids) {
function noUnreadTopics() {
unreadTopics.no_topics_message = 'show';
unreadTopics.show_markallread_button = 'hidden';
callback(unreadTopics);
}
}
function sendUnreadTopics(topicIds) {
Topics.getTopicsByTids(topicIds, uid, function(topicData) {
unreadTopics.topics = topicData;
@ -172,29 +172,29 @@ marked.setOptions({
callback(unreadTopics);
});
}
if (!tids || !tids.length) {
noUnreadTopics();
return;
}
if(uid === 0) {
sendUnreadTopics(tids);
} else {
Topics.hasReadTopics(tids, uid, function(read) {
var unreadTids = tids.filter(function(tid, index, self) {
return read[index] === 0;
});
});
if (!unreadTids || !unreadTids.length) {
noUnreadTopics();
return;
}
sendUnreadTopics(unreadTids);
});
});
}
});
}
@ -202,18 +202,16 @@ marked.setOptions({
Topics.getTopicsByTids = function(tids, current_user, callback, category_id) {
var retrieved_topics = [];
if(!Array.isArray(tids) || tids.length === 0) {
callback(retrieved_topics);
return;
}
function getTopicInfo(topicData, callback) {
function getUserInfo(next) {
user.getUserFields(topicData.uid, ['username'], function(userData) {
next(null, userData);
});
user.getUserFields(topicData.uid, ['username'], next);
}
function hasReadTopic(next) {
@ -256,7 +254,7 @@ marked.setOptions({
if(!topicData) {
return callback(null);
}
getTopicInfo(topicData, function(topicInfo) {
topicData['pin-icon'] = topicData.pinned === '1' ? 'icon-pushpin' : 'none';
@ -274,12 +272,12 @@ marked.setOptions({
if (isTopicVisible(topicData, topicInfo))
retrieved_topics.push(topicData);
callback(null);
callback(null);
});
});
}
async.eachSeries(tids, loadTopic, function(err) {
if(!err) {
callback(retrieved_topics);
@ -290,7 +288,7 @@ marked.setOptions({
Topics.getTopicWithPosts = function(tid, current_user, callback) {
threadTools.exists(tid, function(exists) {
if (!exists)
if (!exists)
return callback(new Error('Topic tid \'' + tid + '\' not found'));
Topics.markAsRead(tid, current_user);
@ -311,8 +309,8 @@ marked.setOptions({
threadTools.privileges(tid, current_user, function(privData) {
next(null, privData);
});
}
}
function getCategoryData(next) {
Topics.getCategoryData(tid, next);
}
@ -323,14 +321,14 @@ marked.setOptions({
callback(err, null);
return;
}
var topicData = results[0],
topicPosts = results[1],
privileges = results[2],
categoryData = results[3];
var main_posts = topicPosts.splice(0, 1);
callback(null, {
'topic_name':topicData.title,
'category_name':categoryData.name,
@ -378,7 +376,7 @@ marked.setOptions({
if (err) {
throw new Error(err);
}
var topicData = results[0],
hasRead = results[1],
teaser = results[2];
@ -389,7 +387,7 @@ marked.setOptions({
topicData.teaser_username = teaser.username || '';
topicData.teaser_timestamp = teaser.timestamp ? utils.relativeTime(teaser.timestamp) : '';
topicData.teaser_userpicture = teaser.picture;
callback(topicData);
});
}
@ -431,7 +429,7 @@ marked.setOptions({
});
});
}
Topics.markAllRead = function(uid, callback) {
RDB.smembers('topics:tid', function(err, tids) {
if(err) {
@ -439,13 +437,13 @@ marked.setOptions({
callback(err, null);
return;
}
if(tids && tids.length) {
for(var i=0; i<tids.length; ++i) {
Topics.markAsRead(tids[i], uid);
}
}
}
callback(null, true);
});
}
@ -459,15 +457,15 @@ marked.setOptions({
}
Topics.markUnRead = function(tid) {
RDB.del('tid:' + tid + ':read_by_uid');
RDB.del('tid:' + tid + ':read_by_uid');
}
Topics.markAsRead = function(tid, uid) {
RDB.sadd(schema.topics(tid).read_by_uid, uid);
Topics.getTopicField(tid, 'cid', function(err, cid) {
categories.isTopicsRead(cid, uid, function(read) {
if(read) {
categories.markAsRead(cid, uid);
@ -480,9 +478,9 @@ marked.setOptions({
var batch = RDB.multi();
for (var i=0, ii=tids.length; i<ii; i++) {
batch.sismember(schema.topics(tids[i]).read_by_uid, uid);
batch.sismember(schema.topics(tids[i]).read_by_uid, uid);
}
batch.exec(function(err, hasRead) {
callback(hasRead);
});
@ -497,9 +495,9 @@ marked.setOptions({
console.log(err);
callback(false);
}
});
});
}
Topics.getTeasers = function(tids, callback) {
var teasers = [];
if (Array.isArray(tids)) {
@ -520,7 +518,10 @@ marked.setOptions({
if (!err) {
posts.getPostFields(pid, ['content', 'uid', 'timestamp'], function(postData) {
user.getUserFields(postData.uid, ['username', 'picture'], function(userData) {
user.getUserFields(postData.uid, ['username', 'picture'], function(err, userData) {
if(err)
return callback(err, null);
var stripped = postData.content,
timestamp = postData.timestamp;
@ -546,34 +547,34 @@ marked.setOptions({
type: 'error',
timeout: 2000,
title: 'Title too short',
message: "Please enter a longer title. At least " + config.minimumTitleLength + " characters.",
message: "Please enter a longer title. At least " + meta.config.minimumTitleLength + " characters.",
alert_id: 'post_error'
});
}
Topics.post = function(uid, title, content, category_id, images, callback) {
if (!category_id)
if (!category_id)
throw new Error('Attempted to post without a category_id');
if(content)
if(content)
content = content.trim();
if(title)
title = title.trim();
if (uid === 0) {
callback(new Error('not-logged-in'), null);
return;
} else if(!title || title.length < config.minimumTitleLength) {
} else if(!title || title.length < meta.config.minimumTitleLength) {
callback(new Error('title-too-short'), null);
return;
} else if (!content || content.length < config.miminumPostLength) {
} else if (!content || content.length < meta.config.miminumPostLength) {
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;
}
@ -604,9 +605,9 @@ marked.setOptions({
'postcount': 0,
'locked': 0,
'deleted': 0,
'pinned': 0
'pinned': 0
});
topicSearch.index(title, tid);
RDB.set('topicslug:' + slug + ':tid', tid);
@ -647,7 +648,7 @@ marked.setOptions({
Topics.getTopicField = function(tid, field, callback) {
RDB.hget('topic:' + tid, field, callback);
}
Topics.getTopicFields = function(tid, fields, callback) {
RDB.hmgetObject('topic:' + tid, fields, function(err, data) {
if(err === null) {
@ -656,7 +657,7 @@ marked.setOptions({
else {
console.log(err);
}
});
});
}
Topics.setTopicField = function(tid, field, value) {
@ -677,7 +678,7 @@ marked.setOptions({
RDB.zadd(schema.topics().recent, timestamp, tid);
Topics.setTopicField(tid, 'lastposttime', timestamp);
}
Topics.addPostToTopic = function(tid, pid) {
RDB.rpush('tid:' + tid + ':posts', pid);
}

@ -1,13 +1,14 @@
var RDB = require('./redis.js'),
async = require('async'),
winston = require('winston');
winston = require('winston'),
user = require('./user');
function upgradeCategory(cid, callback) {
RDB.type('categories:'+ cid +':tid', function(err, type) {
if (type === 'set') {
RDB.smembers('categories:' + cid + ':tid', function(err, tids) {
function moveTopic(tid, callback) {
RDB.hget('topic:' + tid, 'timestamp', function(err, timestamp) {
if(err)
@ -17,16 +18,16 @@ function upgradeCategory(cid, callback) {
callback(null);
});
}
async.each(tids, moveTopic, function(err) {
if(!err) {
RDB.rename('temp_categories:' + cid + ':tid', 'categories:' + cid + ':tid');
callback(null);
}
else
else
callback(err);
});
});
} else {
winston.info('category already upgraded '+ cid);
@ -36,29 +37,28 @@ function upgradeCategory(cid, callback) {
}
function upgradeUser(uid, callback) {
RDB.hmgetObject('user:' + uid, ['joindate', 'postcount', 'reputation'], function(err, userData) {
user.getUserFields(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);
callback(null);
});
}
exports.upgrade = function() {
winston.info('upgrading nodebb now');
var schema = [
function upgradeCategories(next) {
winston.info('upgrading categories');
RDB.lrange('categories:cid', 0, -1, function(err, cids) {
async.each(cids, upgradeCategory, function(err) {
if(!err) {
winston.info('upgraded categories');
@ -69,12 +69,12 @@ exports.upgrade = function() {
});
});
},
function upgradeUsers(next) {
winston.info('upgrading users');
RDB.lrange('userlist', 0, -1, function(err, uids) {
async.each(uids, upgradeUser, function(err) {
if(!err) {
winston.info('upgraded users')
@ -82,19 +82,19 @@ exports.upgrade = function() {
} else {
next(err, null);
}
});
});
});
}
];
async.series(schema, function(err, results) {
if(!err)
winston.info('upgrade complete');
else
else
winston.err(err);
process.exit();
});
}

@ -2,7 +2,8 @@ var utils = require('./../public/src/utils.js'),
RDB = require('./redis.js'),
crypto = require('crypto'),
emailjs = require('emailjs'),
emailjsServer = emailjs.server.connect(config.mailer),
meta = require('./meta.js'),
emailjsServer = emailjs.server.connect(meta.config.mailer),
bcrypt = require('bcrypt'),
marked = require('marked'),
notifications = require('./notifications.js'),
@ -48,7 +49,7 @@ var utils = require('./../public/src/utils.js'),
var gravatar = User.createGravatarURLFromEmail(email);
var timestamp = Date.now();
RDB.hmset('user:'+uid, {
'uid': uid,
'username' : username,
@ -71,7 +72,7 @@ var utils = require('./../public/src/utils.js'),
'banned': 0,
'showemail': 0
});
RDB.set('username:' + username + ':uid', uid);
RDB.set('userslug:'+ userslug +':uid', uid);
@ -89,7 +90,7 @@ var utils = require('./../public/src/utils.js'),
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});
if (password !== undefined) {
@ -102,7 +103,7 @@ var utils = require('./../public/src/utils.js'),
});
});
};
User.delete = function(uid, callback) {
RDB.exists('user:'+uid, function(err, exists) {
if(exists === 1) {
@ -134,9 +135,9 @@ var utils = require('./../public/src/utils.js'),
}
User.unban = function(uid, callback) {
User.setUserField(uid, 'banned', 0, callback);
User.setUserField(uid, 'banned', 0, callback);
}
User.getUserField = function(uid, field, callback) {
RDB.hget('user:' + uid, field, function(err, data) {
if(err === null) {
@ -148,13 +149,7 @@ var utils = require('./../public/src/utils.js'),
}
User.getUserFields = function(uid, fields, callback) {
RDB.hmgetObject('user:' + uid, fields, function(err, data) {
if(err === null) {
callback(data);
} else {
console.log(err);
}
});
RDB.hmgetObject('user:' + uid, fields, callback);
}
User.getMultipleUserFields = function(uids, fields, callback) {
@ -170,7 +165,9 @@ var utils = require('./../public/src/utils.js'),
});
function iterator(uid, callback) {
User.getUserFields(uid, fields, function(userData) {
User.getUserFields(uid, fields, function(err, userData) {
if(err)
return callback(err);
returnData.push(userData);
callback(null);
});
@ -215,10 +212,10 @@ var utils = require('./../public/src/utils.js'),
if(data['signature'] !== undefined && data['signature'].length > 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: [

@ -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 '<script>templates.ready(function(){ajaxify.go("' + url + '", null, "' + tpl + '");});</script>';
};
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<ii; i++) {
(function(route) {
app.get('/' + route, function(req, res) {
if ((route === 'login' || route ==='register') && (req.user && req.user.uid > 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));

@ -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<clients.length; ++i) {
var hs = clients[i].handshake;
@ -114,11 +114,11 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
++anonCount;
}
}
return anonCount;
return anonCount;
}
var uids = getUidsInRoom(rooms[roomName]);
var anonymousCount = getAnonymousCount(roomName);
function userList(users, anonymousCount, userCount) {
@ -127,8 +127,8 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
for (var i = 0, ii=users.length; i<ii; ++i) {
usernames[i] = '<strong>' + '<a href="/users/'+users[i].userslug+'">' + users[i].username + '</a></strong>';
}
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<data.length; ++i) {
var uid = data[i];
if(isUserOnline(uid))
returnData.push(uid);
else
else
returnData.push(0);
}
socket.emit('api:user.get_online_users', returnData);
@ -251,20 +253,24 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
socket.on('api:user.changePassword', function(data, callback) {
user.changePassword(uid, data, callback);
});
socket.on('api:user.updateProfile', function(data, callback) {
user.updateProfile(uid, data, callback);
});
socket.on('api:user.changePicture', function(data, callback) {
var type = data.type;
function updateHeader() {
user.getUserFields(uid, ['picture'], function(fields) {
fields.uid = uid;
socket.emit('api:updateHeader', fields);
callback(true);
user.getUserFields(uid, ['picture'], function(err, fields) {
if(!err && fields) {
fields.uid = uid;
socket.emit('api:updateHeader', fields);
callback(true);
} else {
callback(false);
}
});
}
@ -284,7 +290,7 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
});
socket.on('api:user.follow', function(data, callback) {
if(uid) {
if(uid) {
user.follow(uid, data.uid, callback);
}
});
@ -327,21 +333,21 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
}
return;
}
if(result) {
posts.getTopicPostStats(socket);
socket.emit('event:alert', {
title: 'Thank you for posting',
message: 'You have successfully posted. Click here to view your post.',
type: 'notify',
timeout: 2000
});
}
}
});
});
socket.on('api:topics.markAllRead', function(data, callback) {
topics.markAllRead(uid, function(err, success) {
if(!err && success) {
@ -379,20 +385,20 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
}
return;
}
if(result) {
posts.getTopicPostStats(socket);
socket.emit('event:alert', {
title: 'Reply Successful',
message: 'You have successfully replied. Click here to view your reply.',
type: 'notify',
timeout: 2000
});
}
});
});
@ -514,10 +520,10 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
for(var x=0;x<numSockets;x++) {
userSockets[touid][x].emit('chatMessage', {fromuid:uid, username:username, message:finalMessage});
}
notifications.create(finalMessage, 5, '#', 'notification_'+uid+'_'+touid, function(nid) {
notifications.push(nid, [touid], function(success) {
});
});
});
@ -525,19 +531,19 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
});
socket.on('api:config.get', function(data) {
meta.config.get(function(config) {
meta.configs.get(function(config) {
socket.emit('api:config.get', config);
});
});
socket.on('api:config.set', function(data) {
meta.config.set(data.key, data.value, function(err) {
meta.configs.set(data.key, data.value, function(err) {
if (!err) socket.emit('api:config.set', { status: 'ok' });
});
});
socket.on('api:config.remove', function(key) {
meta.config.remove(key);
meta.configs.remove(key);
});
socket.on('api:composer.push', function(data) {
@ -545,7 +551,7 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
if (parseInt(data.tid) > 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([
@ -628,18 +636,18 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
});
socket.on('api:topic.loadMore', function(data, callback) {
var start = data.after,
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));

Loading…
Cancel
Save