Merge remote-tracking branch 'origin'

v1.18.x
Julian Lam 12 years ago
commit 4993b74c23

@ -16,8 +16,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Read config.js to grab redis info
var fs = require('fs'),
winston = require('winston'),
nconf = require('nconf'),
pkg = require('./package.json'),
url = require('url');
@ -28,11 +28,26 @@ global.env = process.env.NODE_ENV || 'production',
// Configuration setup
nconf.argv().file({ file: __dirname + '/config.json'});
winston.remove(winston.transports.Console);
winston.add(winston.transports.Console, {
colorize:true
});
winston.add(winston.transports.File, {
filename:'error.log',
level:'error'
})
// TODO: remove once https://github.com/flatiron/winston/issues/280 is fixed
winston.err = function(err) {
winston.error(err.stack);
};
// Log GNU copyright info along with server info
console.log('Info: NodeBB v' + pkg.version + ' Copyright (C) 2013 DesignCreatePlay Inc.');
console.log('Info: This program comes with ABSOLUTELY NO WARRANTY.');
console.log('Info: This is free software, and you are welcome to redistribute it under certain conditions.');
console.log('Info: ===');
winston.info('NodeBB v' + pkg.version + ' Copyright (C) 2013 DesignCreatePlay Inc.');
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();
@ -41,8 +56,8 @@ if(nconf.get('upgrade')) {
nconf.set('upload_url', nconf.get('url') + 'uploads/');
global.nconf = nconf;
console.log('Info: Initializing NodeBB v' + pkg.version + ', on port ' + nconf.get('port') + ', using Redis store at ' + nconf.get('redis:host') + ':' + nconf.get('redis:port') + '.');
console.log('Info: Base Configuration OK.');
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');
@ -84,10 +99,10 @@ if(nconf.get('upgrade')) {
//setup scripts to be moved outside of the app in future.
function setup_categories() {
console.log('Info: Checking categories...');
winston.info('Checking categories...');
categories.getAllCategories(function(data) {
if (data.categories.length === 0) {
console.log('Info: Setting up default categories...');
winston.info('Setting up default categories...');
fs.readFile(config.ROOT_DIRECTORY + '/install/data/categories.json', function(err, default_categories) {
default_categories = JSON.parse(default_categories);
@ -98,21 +113,24 @@ if(nconf.get('upgrade')) {
});
console.log('Info: Hardcoding uid 1 as an admin');
winston.info('Hardcoding uid 1 as an admin');
var user = require('./src/user.js');
user.makeAdministrator(1);
} else {
console.log('Info: Categories OK. Found ' + data.categories.length + ' categories.');
winston.info('Categories OK. Found ' + data.categories.length + ' categories.');
}
});
}
setup_categories();
}(global.configuration));
});
} else {
// New install, ask setup questions
if (nconf.get('setup')) console.log('Info: NodeBB Setup Triggered via Command Line');
else console.log('Info: Configuration not found, starting NodeBB setup');
if (nconf.get('setup')) winston.info('NodeBB Setup Triggered via Command Line');
else winston.info('Configuration not found, starting NodeBB setup');
var install = require('./src/install');
@ -124,7 +142,7 @@ if(nconf.get('upgrade')) {
install.setup(function(err) {
if (err) {
console.log('Error: There was a problem completing NodeBB setup: ', err.message);
winston.error('There was a problem completing NodeBB setup: ', err.message);
} else {
if (!nconf.get('setup')) {
process.stdout.write(

@ -2,7 +2,7 @@
"name": "nodebb",
"license": "GPLv3 or later",
"description": "NodeBB Forum",
"version": "0.0.4",
"version": "0.0.5",
"homepage": "http://www.nodebb.org",
"repository": {
"type": "git",
@ -33,7 +33,8 @@
"sitemap": "~0.6.0",
"cheerio": "~0.12.0",
"request": "~2.25.0",
"reds": "~0.2.4"
"reds": "~0.2.4",
"winston": "~0.7.2"
},
"bugs": {
"url": "https://github.com/designcreateplay/NodeBB/issues"

@ -197,6 +197,12 @@ footer.footer {
font-weight:bold;
}
.account-block {
div {
padding-bottom:10px;
}
}
.account-picture-block{
display:inline-block;
vertical-align:top;
@ -213,7 +219,6 @@ footer.footer {
.user-profile-picture {
width:128px;
margin-bottom:10px;
}
.user-picture-label {
@ -392,7 +397,7 @@ body .navbar .nodebb-inline-block {
#admin-redis-info {
span {
display:inline-block;
width:200px;
width:220px;
}
}
@ -829,7 +834,7 @@ body .navbar .nodebb-inline-block {
.form-search {
float: left;
margin-top: 5px;
margin-bottom:0px;
margin-bottom: 5px;
}
.search-result-post {

@ -117,8 +117,6 @@
.topic-title {
width: auto;
white-space: nowrap;
text-overflow:ellipsis;
overflow: hidden;
margin: 0;
padding: 0;

@ -26,6 +26,7 @@ var ajaxify = {};
};
ajaxify.go = function(url, callback, template, quiet) {
$(window).off('scroll');
// leave room and join global
app.enter_room('global');

@ -5,11 +5,12 @@ var socket,
(function() {
var showWelcomeMessage = false;
function loadConfig() {
$.ajax({
url: RELATIVE_PATH + '/config.json?v=' + new Date().getTime(),
url: RELATIVE_PATH + '/api/config',
success: function(data) {
API_URL = data.api_url;
@ -29,10 +30,6 @@ var socket,
app.alert(data);
});
socket.on('event:consolelog', function(data) {
console.log(data);
});
socket.on('connect', function(data){
if(reconnecting) {
setTimeout(function(){
@ -286,7 +283,8 @@ var socket,
});
}
if(location.href.indexOf('loggedin') !== -1) {
if(showWelcomeMessage) {
showWelcomeMessage = false;
if(document.readyState !== 'complete') {
$(document).ready(showAlert);
} else {
@ -371,6 +369,8 @@ var socket,
})
});
showWelcomeMessage = location.href.indexOf('loggedin') !== -1;
loadConfig();

@ -8,6 +8,11 @@
return (parent.attr('data-admin') !== "0");
}
function isUserBanned(element) {
var parent = $(element).parents('.users-box');
return (parent.attr('data-banned') !== "" && parent.attr('data-banned') !== "0");
}
function getUID(element) {
var parent = $(element).parents('.users-box');
return parent.attr('data-uid');
@ -34,6 +39,20 @@
deleteBtn.show();
});
jQuery('.ban-btn').each(function(index, element) {
var banBtn = $(element);
var isAdmin = isUserAdmin(banBtn);
var isBanned = isUserBanned(banBtn);
if(isAdmin)
banBtn.addClass('disabled');
else if(isBanned)
banBtn.addClass('btn-warning');
else
banBtn.removeClass('btn-warning');
});
jQuery('.admin-btn').on('click', function() {
var adminBtn = $(this);
var isAdmin = isUserAdmin(adminBtn);
@ -74,13 +93,38 @@
return false;
});
jQuery('.ban-btn').on('click', function() {
var banBtn = $(this);
var isAdmin = isUserAdmin(banBtn);
var isBanned = isUserBanned(banBtn);
var parent = banBtn.parents('.users-box');
var uid = getUID(banBtn);
if(!isAdmin) {
if(isBanned) {
socket.emit('api:admin.user.unbanUser', uid);
banBtn.removeClass('btn-warning');
parent.attr('data-banned', 0);
} else {
bootbox.confirm('Do you really want to ban "' + parent.attr('data-username') +'"?', function(confirm) {
socket.emit('api:admin.user.banUser', uid);
banBtn.addClass('btn-warning');
parent.attr('data-banned', 1);
});
}
}
return false;
});
}
jQuery('document').ready(function() {
var yourid = templates.get('yourid');
var timeoutId = 0;
var yourid = templates.get('yourid'),
timeoutId = 0,
loadingMoreUsers = false;
var url = window.location.href,
parts = url.split('/'),
@ -114,7 +158,6 @@
socket.removeAllListeners('api:admin.user.search');
socket.on('api:admin.user.search', function(data) {
var html = templates.prepare(templates['admin/users'].blocks['users']).parse({
users: data
}),
@ -139,6 +182,45 @@
initUsers();
});
function onUsersLoaded(users) {
var html = templates.prepare(templates['admin/users'].blocks['users']).parse({ users: users });
$('#users-container').append(html);
}
function loadMoreUsers() {
var set = '';
if(active === 'latest') {
set = 'users:joindate';
} else if(active === 'sort-posts') {
set = 'users:postcount';
} else if(active === 'sort-reputation') {
set = 'users:reputation';
}
if(set) {
loadingMoreUsers = true;
socket.emit('api:users.loadMore', {
set: set,
after: $('#users-container').children().length
}, function(data) {
if(data.users.length) {
onUsersLoaded(data.users);
}
loadingMoreUsers = false;
});
}
}
$('#load-more-users-btn').on('click', loadMoreUsers);
$(window).off('scroll').on('scroll', function() {
var bottom = (document.body.offsetHeight - $(window).height()) * 0.9;
if (document.body.scrollTop > bottom && !loadingMoreUsers) {
loadMoreUsers();
}
});
});
}());

@ -122,10 +122,9 @@
}
$(window).off('scroll').on('scroll', function(ev) {
var windowHeight = document.body.offsetHeight - $(window).height(),
half = windowHeight / 2;
var bottom = (document.body.offsetHeight - $(window).height()) * 0.9;
if (document.body.scrollTop > half && !loadingMoreTopics) {
if (document.body.scrollTop > bottom && !loadingMoreTopics) {
loadMoreTopics(cid);
}
});

@ -27,11 +27,15 @@
url: RELATIVE_PATH + '/login',
data: loginData,
success: function(data, textStatus, jqXHR) {
if(!data.success) {
$('#login-error-notify').html(data.message).show();
} else {
$('#login-error-notify').hide();
window.location.replace(RELATIVE_PATH + "/?loggedin");
}
},
error : function(data, textStatus, jqXHR) {
$('#login-error-notify').show().delay(1000).fadeOut(250);
$('#login-error-notify').show();
},
dataType: 'json',
async: true,

@ -69,10 +69,9 @@
}
$(window).off('scroll').on('scroll', function() {
var windowHeight = document.body.offsetHeight - $(window).height(),
half = windowHeight / 2;
var bottom = (document.body.offsetHeight - $(window).height()) * 0.9;
if (document.body.scrollTop > half && !loadingMoreTopics) {
if (document.body.scrollTop > bottom && !loadingMoreTopics) {
loadMoreTopics();
}
});

@ -202,10 +202,9 @@
// Infinite scrolling of posts
$(window).off('scroll').on('scroll', function() {
var windowHeight = document.body.offsetHeight - $(window).height(),
half = windowHeight / 2;
var bottom = (document.body.offsetHeight - $(window).height()) * 0.9;
if (document.body.scrollTop > half && !app.infiniteLoaderActive && $('#post-container').children().length) {
if (document.body.scrollTop > bottom && !app.infiniteLoaderActive && $('#post-container').children().length) {
app.loadMorePosts(tid);
}
});
@ -255,11 +254,9 @@
var element = $(this).find('i');
if(element.attr('class') == 'icon-star-empty') {
element.attr('class', 'icon-star');
socket.emit('api:posts.favourite', {pid: pid, room_id: app.current_room});
}
else {
element.attr('class', 'icon-star-empty');
socket.emit('api:posts.unfavourite', {pid: pid, room_id: app.current_room});
}
});
@ -388,7 +385,14 @@
});
socket.on('api:posts.favourite', function(data) {
if (data.status !== 'ok' && data.pid) {
if (data.status === 'ok' && data.pid) {
var favEl = document.querySelector('.post_rep_' + data.pid).nextSibling;
if (favEl) favEl.className = 'icon-star';
}
});
socket.on('api:posts.unfavourite', function(data) {
if (data.status === 'ok' && data.pid) {
var favEl = document.querySelector('.post_rep_' + data.pid).nextSibling;
if (favEl) favEl.className = 'icon-star-empty';
}

@ -84,10 +84,9 @@
}
$(window).off('scroll').on('scroll', function() {
var windowHeight = document.body.offsetHeight - $(window).height(),
half = windowHeight / 2;
var bottom = (document.body.offsetHeight - $(window).height()) * 0.9;
if (document.body.scrollTop > half && !loadingMoreTopics) {
if (document.body.scrollTop > bottom && !loadingMoreTopics) {
loadMoreTopics();
}
});

@ -2,6 +2,7 @@
$(document).ready(function() {
var timeoutId = 0;
var loadingMoreUsers = false;
var url = window.location.href,
parts = url.split('/'),
@ -74,6 +75,46 @@
$(element).html(app.addCommas($(element).html()));
});
function onUsersLoaded(users) {
var html = templates.prepare(templates['users'].blocks['users']).parse({ users: users });
$('#users-container').append(html);
}
function loadMoreUsers() {
var set = '';
if(active === 'users-latest' || active === 'users') {
set = 'users:joindate';
} else if(active === 'users-sort-posts') {
set = 'users:postcount';
} else if(active === 'users-sort-reputation') {
set = 'users:reputation';
}
if(set) {
loadingMoreUsers = true;
socket.emit('api:users.loadMore', {
set: set,
after: $('#users-container').children().length
}, function(data) {
if(data.users.length) {
onUsersLoaded(data.users);
} else {
$('#load-more-users-btn').addClass('disabled');
}
loadingMoreUsers = false;
});
}
}
$('#load-more-users-btn').on('click', loadMoreUsers);
$(window).off('scroll').on('scroll', function() {
var bottom = (document.body.offsetHeight - $(window).height()) * 0.9;
if (document.body.scrollTop > bottom && !loadingMoreUsers) {
loadMoreUsers();
}
});
});
}());

@ -299,22 +299,22 @@ define(['taskbar'], function(taskbar) {
titleEl.value = titleEl.value.trim();
bodyEl.value = bodyEl.value.trim();
if (titleEl.value.length < 3) {
if (titleEl.value.length < config.minimumTitleLength) {
return app.alert({
type: 'error',
timeout: 2000,
title: 'Title too short',
message: "Please enter a longer title. At least 3 characters.",
message: "Please enter a longer title. At least " + config.minimumTitleLength+ " characters.",
alert_id: 'post_error'
});
}
if (bodyEl.value.length < 8) {
if (bodyEl.value.length < config.minimumPostLength) {
return app.alert({
type: 'error',
timeout: 2000,
title: 'Content too short',
message: "Please enter a longer post. At least 8 characters.",
message: "Please enter a longer post. At least " + config.minimumPostLength + " characters.",
alert_id: 'post_error'
});
}

@ -17,13 +17,16 @@
<div class="row-fluid">
<div class="span2" style="text-align: center; margin-bottom:20px;">
<div class="span2 account-block" style="text-align: center; margin-bottom:20px;">
<div class="account-picture-block">
<img src="{picture}" class="user-profile-picture img-polaroid"/>
</div>
<div class="account-online-status">
<span><i class="icon-circle-blank"></i> <span>offline</span></span>
</div>
<div class="{show_banned}">
<span class="label label-important">banned</span>
</div>
<div id="user-actions">
<a id="follow-btn" href="#" class="btn hide">Follow</a>
<a id="unfollow-btn" href="#" class="btn hide">Unfollow</a>

@ -16,6 +16,7 @@
<hr/>
<span>Total Connections Received</span> <span class="text-right">{total_connections_received}</span><br/>
<span>Total Commands Processed</span> <span class="text-right">{total_commands_processed}</span><br/>
<span>Instantaneous Ops. Per Second</span> <span class="text-right">{instantaneous_ops_per_sec}</span><br/>
<hr/>
<span>Keyspace Hits</span> <span class="text-right">{keyspace_hits}</span><br/>
<span>Keyspace Misses</span> <span class="text-right">{keyspace_misses}</span><br/>

@ -48,6 +48,16 @@
</div>
</form>
<form>
<h3>Post Settings</h3>
<div class="alert alert-notify">
<strong>Post Delay</strong><br /> <input type="text" class="" value="10000" data-field="postDelay"><br />
<strong>Minimum Title Length</strong><br /> <input type="text" class="" value="3" data-field="minimumTitleLength"><br />
<strong>Minimum Post Length</strong><br /> <input type="text" class="" value="8" data-field="minimumPostLength"><br />
</div>
</form>
<button class="btn btn-large btn-primary" id="save">Save</button>
<script>

@ -14,9 +14,9 @@
<span id="user-notfound-notify" class="label label-important hide">User not found!</span><br/>
</div>
<ul class="users">
<ul id="users-container" class="users">
<!-- BEGIN users -->
<div class="users-box" data-uid="{users.uid}" data-admin="{users.administrator}" data-username="{users.username}">
<div class="users-box" data-uid="{users.uid}" data-admin="{users.administrator}" data-username="{users.username}" data-banned="{users.banned}">
<a href="/users/{users.userslug}">
<img src="{users.picture}" class="img-polaroid"/>
</a>
@ -37,10 +37,16 @@
<div>
<a href="#" class="btn delete-btn btn-danger">Delete</a>
</div>
<div>
<a href="#" class="btn ban-btn">Ban</a>
</div>
</div>
<!-- END users -->
</ul>
<div class="text-center {loadmore_display}">
<button id="load-more-users-btn" class="btn">Load More</button>
</div>
<input type="hidden" template-variable="yourid" value="{yourid}" />

@ -62,11 +62,12 @@
<li><a href="#"><i class="icon-refresh icon-spin"></i> Loading Notifications</a></li>
</ul>
</li>
<form id="search-form"
class="form-search form-inline" action="" method="GET">
<li>
<form id="search-form" class="form-search form-inline" action="" method="GET">
<input type="text" name="query" class="input-medium search-query">
<button type="submit" class="btn hide">Search</button>
</form>
</li>
</ul>
</div>

@ -110,7 +110,6 @@
contentEl.addEventListener('click', function(e) {
if (e.target.hasAttribute('data-path')) {
var href = 'install/' + e.target.getAttribute('data-path');
console.log(href);
if (!e.target.disabled) ajaxify.go(href);
}
}, false);

@ -14,7 +14,7 @@
<button class="btn btn-primary" id="login" type="submit">Login</button> &nbsp; <a href="/reset">Forgot Password?</a>
</form>
<span id="login-error-notify" class="label label-important hide">Invalid username/password</span><br/>
<div id="login-error-notify" class="alert alert-danger hide">Invalid username/password</div>
</div>
<div class="well span6 {alternate_logins:display}">

@ -89,6 +89,7 @@
<i class="icon-star"></i><span class="user_rep_{posts.uid} formatted-number">{posts.user_rep}</span>
<div id="ids_{posts.pid}_{posts.uid}" class="chat hidden-phone" title="Chat"><i class="icon-comment"></i></div>
</div>
<span class="label label-important {posts.show_banned}">banned</span>
</div>
<div class="span11 span12-tablet">
<div class="post-block">

@ -14,7 +14,7 @@
<span id="user-notfound-notify" class="label label-important hide">User not found!</span><br/>
</div>
<ul class="users">
<ul id="users-container" class="users">
<!-- BEGIN users -->
<div class="users-box">
<a href="/users/{users.userslug}">
@ -36,4 +36,8 @@
</ul>
</div>
<div class="text-center {loadmore_display}">
<button id="load-more-users-btn" class="btn">Load More</button>
</div>
<script type="text/javascript" src="{relative_path}/src/forum/users.js"></script>

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

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

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

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

@ -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)',
@ -85,6 +86,10 @@ var async = require('async'),
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);
});
},

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

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

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

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

@ -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
});
@ -193,14 +200,13 @@ var RDB = require('./redis.js'),
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);

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

@ -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,38 +65,29 @@ 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) {
user.getUsers('users:joindate', 0, 49, function(err, data) {
res.json({ search_display: 'none', users:data, yourid:req.user.uid });
});
});
@ -139,6 +131,9 @@ var user = require('./../user.js'),
for(var i in data) {
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);
}
}

@ -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) {
@ -14,6 +15,19 @@ var user = require('./../user.js'),
});
});
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;
categories.getAllCategories(function(data) {
@ -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);

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

@ -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']);
});
});
});
@ -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,6 +371,7 @@ var user = require('./../user.js'),
else
data.emailClass = "hide";
data.show_banned = data.banned === '1'?'':'hide';
data.uid = uid;
data.yourid = callerUID;

@ -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);
}
});
@ -297,7 +298,6 @@ var RDB = require('./redis.js'),
}
}
// If we got here, nothing was found...
callback(new Error('no-undeleted-pids-found'));
});
}

@ -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<postData.length; ++i) {
postData[i].fav_star_class = fav_data[postData[i].pid] ? 'icon-star' : 'icon-star-empty';
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);
@ -149,6 +150,10 @@ marked.setOptions({
Topics.getTopicsByTids(topicIds, uid, function(topicData) {
unreadTopics.topics = topicData;
unreadTopics.nextStart = start + tids.length;
if(!topicData || topicData.length === 0)
unreadTopics.no_topics_message = 'show';
if(uid === 0 || topicData.length === 0)
unreadTopics.show_markallread_button = 'hidden';
callback(unreadTopics);
});
}
@ -190,9 +195,9 @@ marked.setOptions({
function getTopicInfo(topicData, callback) {
function getUserName(next) {
user.getUserField(topicData.uid, 'username', function(username) {
next(null, username);
function getUserInfo(next) {
user.getUserFields(topicData.uid, ['username'], function(userData) {
next(null, userData);
});
}
@ -215,17 +220,13 @@ marked.setOptions({
});
}
async.parallel([getUserName, hasReadTopic, getTeaserInfo, getPrivileges], function(err, results) {
var username = results[0],
hasReadTopic = results[1],
teaserInfo = results[2],
privileges = results[3];
async.parallel([getUserInfo, hasReadTopic, getTeaserInfo, getPrivileges], function(err, results) {
callback({
username: username,
hasread: hasReadTopic,
teaserInfo: teaserInfo,
privileges: privileges
username: results[0].username,
userbanned: results[0].banned,
hasread: results[1],
teaserInfo: results[2],
privileges: results[3]
});
});
}
@ -508,8 +509,10 @@ marked.setOptions({
var stripped = postData.content,
timestamp = postData.timestamp;
if(postData.content)
stripped = utils.strip_tags(postTools.markdownToHTML(postData.content));
if(postData.content) {
stripped = postData.content.replace(/>.+\n\n/, '');
stripped = utils.strip_tags(postTools.markdownToHTML(stripped));
}
callback(null, {
"text": stripped,
@ -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;
}

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

@ -41,12 +41,13 @@ 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,
@ -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);
});
@ -122,6 +128,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) {
if(err === null) {
@ -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) {

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

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

Loading…
Cancel
Save