Merge branch 'master' of github.com:designcreateplay/NodeBB

v1.18.x
Julian Lam 11 years ago
commit dc90db74c0

12
.gitignore vendored

@ -1,7 +1,3 @@
#################
## npm
#################
npm-debug.log
node_modules/
sftp-config.json
@ -9,12 +5,10 @@ config.json
public/src/nodebb.min.js
public/config.json
public/css/*.css
public/themes/*
!/public/themes/vanilla
!/public/themes/cerulean
!/public/themes/modern
*.sublime-project
*.sublime-workspace
plugins/*
.project
*.swp
Vagrantfile
.vagrant
provision.sh

@ -121,6 +121,10 @@
winston.warn('Configuration not found, starting NodeBB setup');
}
nconf.file({
file: __dirname + '/config.json'
});
var install = require('./src/install');
winston.info('Welcome to NodeBB!');

@ -42,7 +42,7 @@
"uglify-js": "~2.4.0",
"validator": "~1.5.1",
"nodebb-plugin-mentions": "~0.1.14",
"nodebb-plugin-markdown": "~0.1.7",
"nodebb-plugin-markdown": "~0.1.8",
"nodebb-theme-vanilla": "designcreateplay/nodebb-theme-vanilla",
"nodebb-theme-cerulean": "0.0.5",
"cron": "~1.0.1"

@ -339,6 +339,7 @@ var socket,
chatModal = chat.getModal(touid);
}
chat.load(chatModal.attr('UUID'));
chat.center(chatModal);
});
}

@ -27,12 +27,11 @@ define(function () {
return false;
});
var new_post = document.getElementById('new_post');
new_post.onclick = function () {
$('#new_post').on('click', function () {
require(['composer'], function (cmp) {
cmp.push(0, cid);
});
}
});
ajaxify.register_events([
'event:new_topic'
@ -59,11 +58,12 @@ define(function () {
li.innerHTML = '<a href="/user/' + posts[i].userslug + '"><img title="' + posts[i].username + '" style="width: 48px; height: 48px; /*temporary*/" class="img-rounded" src="' + posts[i].picture + '" class="" /></a>' +
'<a href="/topic/' + posts[i].topicSlug + '#' + posts[i].pid + '">' +
'<strong><span>'+ posts[i].username + '</span></strong>' +
'<p>' +
posts[i].content +
'</p>' +
'<p class="meta"><strong>' + posts[i].username + '</strong></span> -<span class="timeago" title="' + posts[i].relativeTime + '"></span></p>' +
'</a>';
'</a>' +
'<span class="timeago pull-right" title="' + posts[i].relativeTime + '"></span>';
frag.appendChild(li.cloneNode(true));
recent_replies.appendChild(frag);
@ -106,9 +106,27 @@ define(function () {
}
socket.emit('api:categories.getRecentReplies', templates.get('category_id'));
addActiveUser(data);
$('#topics-container span.timeago').timeago();
}
function addActiveUser(data) {
var activeUser = $('.category-sidebar .active-users').find('a[data-uid="' + data.uid + '"]');
if(!activeUser.length) {
var newUser = templates.prepare(templates['category'].blocks['active_users']).parse({
active_users: [{
uid: data.uid,
username: data.username,
userslug: data.userslug,
picture: data.teaser_userpicture
}]
});
$(newUser).appendTo($('.category-sidebar .active-users'));
}
}
Category.onTopicsLoaded = function(topics) {
var html = templates.prepare(templates['category'].blocks['topics']).parse({

@ -1,28 +1,4 @@
(function() {
var stats_users = document.getElementById('stats_users'),
stats_topics = document.getElementById('stats_topics'),
stats_posts = document.getElementById('stats_posts'),
stats_online = document.getElementById('stats_online'),
user_label = document.getElementById('user_label');
socket.emit('user.count', {});
socket.on('user.count', function(data) {
stats_users.innerHTML = utils.makeNumberHumanReadable(data.count);
stats_users.title = data.count;
});
socket.emit('post.stats');
socket.on('post.stats', function(data) {
stats_topics.innerHTML = utils.makeNumberHumanReadable(data.topics);
stats_topics.title = data.topics;
stats_posts.innerHTML = utils.makeNumberHumanReadable(data.posts);
stats_posts.title = data.posts;
});
socket.emit('api:user.active.get');
socket.on('api:user.active.get', function(data) {
stats_online.innerHTML = data.users;
});
socket.emit('api:updateHeader', {
fields: ['username', 'picture', 'userslug']

@ -0,0 +1,30 @@
define(function() {
var home = {};
home.init = function() {
ajaxify.register_events([
'user.count',
'post.stats',
'api:user.active.get'
]);
socket.emit('user.count', {});
socket.on('user.count', function(data) {
$('#stats_users').html(utils.makeNumberHumanReadable(data.count)).attr('title', data.count);
});
socket.emit('post.stats');
socket.on('post.stats', function(data) {
$('#stats_topics').html(utils.makeNumberHumanReadable(data.topics)).attr('title', data.topics);
$('#stats_posts').html(utils.makeNumberHumanReadable(data.posts)).attr('title', data.posts);
});
socket.emit('api:user.active.get');
socket.on('api:user.active.get', function(data) {
$('#stats_online').html(data.users);
});
}
return home;
});

@ -85,7 +85,7 @@ define(['taskbar'], function(taskbar) {
return chatModal;
}
function center(chatModal) {
module.center = function(chatModal) {
chatModal.css("position", "fixed");
chatModal.css("top", "100px");
chatModal.css("left", Math.max(0, (($(window).width() - $(chatModal).outerWidth()) / 2) + $(window).scrollLeft()) + "px");
@ -95,7 +95,6 @@ define(['taskbar'], function(taskbar) {
module.load = function(uuid) {
var chatModal = $('div[UUID="'+uuid+'"]');
chatModal.show();
center(chatModal);
module.bringModalToTop(chatModal);
checkOnlineStatus(chatModal);
}

@ -80,9 +80,10 @@
if (keys.hasOwnProperty(key)) {
var variables = keys[key].split(/[,][?\s+]/);
var parsedKey = keys[key].replace('[[', '').replace(']]', '').split(':'),
languageFile = parsedKey[0];
var parsedKey = keys[key].replace('[[', '').replace(']]', '').split(':');
if (!(parsedKey[0] && parsedKey[1])) continue;
var languageFile = parsedKey[0];
parsedKey = parsedKey[1].split(',')[0];
if (files.loaded[languageFile]) {

@ -76,9 +76,9 @@
<div class="block-header">
[[category:sidebar.active_participants]]
</div>
<div class="block-content">
<div class="block-content active-users">
<!-- BEGIN active_users -->
<a href="/user/{active_users.userslug}"><img title="{active_users.username}" src="{active_users.picture}" class="img-rounded" /></a>
<a data-uid="{active_users.uid}" href="/user/{active_users.userslug}"><img title="{active_users.username}" src="{active_users.picture}" class="img-rounded" /></a>
<!-- END active_users -->
</div>
</div>

@ -60,29 +60,6 @@
<footer id="footer" class="container footer">
<div class="row footer-stats">
<div class="col-md-3 col-xs-6">
<div class="stats-card well">
<h2><span id="stats_online"></span><br /><small>[[footer:stats.online]]</small></h2>
</div>
</div>
<div class="col-md-3 col-xs-6">
<div class="stats-card well">
<h2><span id="stats_users"></span><br /><small>[[footer:stats.users]]</small></h2>
</div>
</div>
<div class="col-md-3 col-xs-6">
<div class="stats-card well">
<h2><span id="stats_topics"></span><br /><small>[[footer:stats.topics]]</small></h2>
</div>
</div>
<div class="col-md-3 col-xs-6">
<div class="stats-card well">
<h2><span id="stats_posts"></span><br /><small>[[footer:stats.posts]]</small></h2>
</div>
</div>
</div>
<div class="copyright">Copyright &copy; 2013 <a target="_blank" href="http://www.nodebb.org">NodeBB</a> by <a target="_blank" href="https://github.com/psychobunny">psychobunny</a>, <a href="https://github.com/julianlam" target="_blank">julianlam</a>, <a href="https://github.com/barisusakli" target="_blank">barisusakli</a> from <a target="_blank" href="http://www.designcreateplay.com">designcreateplay</a></div>
</footer>

@ -26,4 +26,27 @@
</a>
</div>
<!-- END categories -->
</div>
</div>
<div class="row footer-stats">
<div class="col-md-3 col-xs-6">
<div class="stats-card well">
<h2><span id="stats_online"></span><br /><small>[[footer:stats.online]]</small></h2>
</div>
</div>
<div class="col-md-3 col-xs-6">
<div class="stats-card well">
<h2><span id="stats_users"></span><br /><small>[[footer:stats.users]]</small></h2>
</div>
</div>
<div class="col-md-3 col-xs-6">
<div class="stats-card well">
<h2><span id="stats_topics"></span><br /><small>[[footer:stats.topics]]</small></h2>
</div>
</div>
<div class="col-md-3 col-xs-6">
<div class="stats-card well">
<h2><span id="stats_posts"></span><br /><small>[[footer:stats.posts]]</small></h2>
</div>
</div>
</div>

@ -96,7 +96,7 @@ var RDB = require('./redis.js'),
}
function getActiveUsers(next) {
user.getMultipleUserFields(active_users, ['username', 'userslug', 'picture'], function(err, users) {
user.getMultipleUserFields(active_users, ['uid', 'username', 'userslug', 'picture'], function(err, users) {
next(err, users);
});
}
@ -425,7 +425,8 @@ var RDB = require('./redis.js'),
};
Categories.addActiveUser = function(cid, uid) {
RDB.sadd('cid:' + cid + ':active_users', uid);
if(parseInt(uid, 10))
RDB.sadd('cid:' + cid + ':active_users', uid);
};
Categories.removeActiveUser = function(cid, uid) {

@ -12,44 +12,44 @@ var async = require('async'),
questions: [{
name: 'base_url',
description: 'URL of this installation',
'default': 'http://localhost',
'default': nconf.get('base_url') || 'http://localhost',
pattern: /^http(?:s)?:\/\//,
message: 'Base URL must begin with \'http://\' or \'https://\'',
}, {
name: 'port',
description: 'Port number of your NodeBB',
'default': 4567,
'default': nconf.get('port') || 4567,
pattern: /[0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]/,
message: 'Please enter a value betweeen 1 and 65535'
}, {
name: 'use_port',
description: 'Use a port number to access NodeBB?',
'default': 'y',
'default': (nconf.get('use_port') ? 'y' : 'n') || 'y',
pattern: /y[es]*|n[o]?/,
message: 'Please enter \'yes\' or \'no\'',
}, {
name: 'secret',
description: 'Please enter a NodeBB secret',
'default': utils.generateUUID()
'default': nconf.get('secret') || utils.generateUUID()
}, {
name: 'redis:host',
description: 'Host IP or address of your Redis instance',
'default': '127.0.0.1'
'default': nconf.get('redis:host') || '127.0.0.1'
}, {
name: 'redis:port',
description: 'Host port of your Redis instance',
'default': 6379
'default': nconf.get('redis:port') || 6379
}, {
name: 'redis:password',
description: 'Password of your Redis database'
}, {
name: "redis:database",
description: "Which database to use (0..n)",
'default': 0
'default': nconf.get('redis:database') || 0
}, {
name: 'bind_address',
description: 'IP or Hostname to bind to',
'default': '0.0.0.0'
'default': nconf.get('bind_address') || '0.0.0.0'
}],
setup: function (callback) {
async.series([

@ -17,8 +17,31 @@ var fs = require('fs'),
if (this.initialized) return;
if (global.env === 'development') winston.info('[plugins] Initializing plugins system');
this.reload(function(err) {
if (err) {
if (global.env === 'development') winston.info('[plugins] NodeBB encountered a problem while loading plugins', err.message);
return;
}
if (global.env === 'development') winston.info('[plugins] Plugins OK');
plugins.initialized = true;
plugins.readyEvent.emit('ready');
});
},
ready: function(callback) {
if (!this.initialized) this.readyEvent.once('ready', callback);
else callback();
},
initialized: false,
reload: function(callback) {
var _self = this;
// Resetting all local plugin data
this.loadedHooks = {};
this.staticDirs = {};
this.cssFiles.length = 0;
// Read the list of activated plugins and require their libraries
async.waterfall([
function(next) {
@ -27,10 +50,8 @@ var fs = require('fs'),
function(plugins, next) {
if (plugins && Array.isArray(plugins) && plugins.length > 0) {
async.each(plugins, function(plugin, next) {
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);
var modulePath = path.join(__dirname, '../node_modules/', plugin);
if (fs.existsSync(modulePath)) _self.loadPlugin(modulePath, next);
else {
if (global.env === 'development') winston.warn('[plugins] Plugin \'' + plugin + '\' not found');
next(); // Ignore this plugin silently
@ -49,23 +70,8 @@ var fs = require('fs'),
next();
}
], function(err) {
if (err) {
if (global.env === 'development') winston.info('[plugins] NodeBB encountered a problem while loading plugins', err.message);
return;
}
if (global.env === 'development') winston.info('[plugins] Plugins OK');
_self.initialized = true;
_self.readyEvent.emit('ready');
});
},
ready: function(callback) {
if (!this.initialized) this.readyEvent.once('ready', callback);
else callback();
], callback);
},
initialized: false,
loadPlugin: function(pluginPath, callback) {
var _self = this;
@ -82,16 +88,25 @@ var fs = require('fs'),
fs.exists(libraryPath, function(exists) {
if (exists) {
_self.libraries[pluginData.id] = require(libraryPath);
if (!_self.libraries[pluginData.id]) {
_self.libraries[pluginData.id] = require(libraryPath);
}
// Register hooks for this plugin
if (pluginData.hooks && Array.isArray(pluginData.hooks) && pluginData.hooks.length > 0) {
async.each(pluginData.hooks, function(hook, next) {
_self.registerHook(pluginData.id, hook, next);
}, next);
}
} else {
winston.warn('[plugins.reload] Library not found for plugin: ' + pluginData.id);
next();
}
});
} else next();
} else {
winston.warn('[plugins.reload] Library not found for plugin: ' + pluginData.id);
next();
}
},
function(next) {
// Static Directories for Plugins
@ -219,15 +234,18 @@ var fs = require('fs'),
return;
}
// (De)activation Hooks
plugins.fireHook('action:plugin.' + (active ? 'de' : '') + 'activate', id);
// Reload meta data
plugins.reload(function() {
// (De)activation Hooks
plugins.fireHook('action:plugin.' + (active ? 'de' : '') + 'activate', id);
if (callback) {
callback({
id: id,
active: !active
});
}
if (callback) {
callback({
id: id,
active: !active
});
}
});
});
});
},

@ -132,12 +132,6 @@ var RDB = require('./redis.js'),
});
};
Posts.filterBannedPosts = function(posts) {
return posts.filter(function(post) {
return post.user_banned === '0';
});
}
// TODO: this function is never called except from some debug route. clean up?
Posts.getPostData = function(pid, callback) {
RDB.hgetall('post:' + pid, function(err, data) {
@ -146,8 +140,9 @@ var RDB = require('./redis.js'),
if (!err) callback(newData);
else callback(data);
});
} else
console.log(err);
} else {
winston.error(err);
}
});
}

@ -0,0 +1,25 @@
var nconf = require('nconf'),
path = require('path'),
fs = require('fs'),
Plugins = require('../plugins'),
PluginRoutes = function(app) {
// Static Assets
app.get('/plugins/:id/*', function(req, res) {
var relPath = req.url.replace('/plugins/' + req.params.id, '');
if (Plugins.staticDirs[req.params.id]) {
var fullPath = path.join(Plugins.staticDirs[req.params.id], relPath);
fs.exists(fullPath, function(exists) {
if (exists) {
res.sendfile(fullPath);
} else {
res.redirect('/404');
}
})
} else {
res.redirect('/404');
}
});
};
module.exports = PluginRoutes;

@ -336,7 +336,7 @@ var RDB = require('./redis.js'),
topicData.badgeclass = (topicInfo.hasread && current_user != 0) ? '' : 'badge-important';
topicData.teaser_text = topicInfo.teaserInfo.text || '',
topicData.teaser_username = topicInfo.teaserInfo.username || '';
topicData.teaser_userpicture = topicInfo.teaserInfo.picture || '';
topicData.teaser_userpicture = topicInfo.teaserInfo.picture || require('gravatar').url('', {}, https = nconf.get('https'));
topicData.teaser_pid = topicInfo.teaserInfo.pid;
topicData.teaser_timestamp = topicInfo.teaserInfo.timestamp ? (new Date(parseInt(topicInfo.teaserInfo.timestamp, 10)).toISOString()) : '';
@ -461,6 +461,7 @@ var RDB = require('./redis.js'),
topicData.badgeclass = hasRead ? '' : 'badge-important';
topicData.teaser_text = teaser.text || '';
topicData.teaser_username = teaser.username || '';
topicData.userslug = teaser.userslug || '';
topicData.teaser_timestamp = teaser.timestamp ? (new Date(parseInt(teaser.timestamp,10)).toISOString()) : '';
topicData.teaser_userpicture = teaser.picture;
@ -606,7 +607,7 @@ var RDB = require('./redis.js'),
if (!err) {
posts.getPostFields(pid, ['pid', 'content', 'uid', 'timestamp'], function(postData) {
user.getUserFields(postData.uid, ['username', 'picture'], function(err, userData) {
user.getUserFields(postData.uid, ['username', 'userslug', 'picture'], function(err, userData) {
if (err)
return callback(err, null);
@ -615,6 +616,7 @@ var RDB = require('./redis.js'),
returnObj = {
"pid": postData.pid,
"username": userData.username,
"userslug": userData.userslug,
"picture": userData.picture,
"timestamp": timestamp
};

@ -151,19 +151,6 @@ var express = require('express'),
},
function(next) {
async.parallel([
function(next) {
// Static Directories for NodeBB Plugins
plugins.ready(function () {
for (d in plugins.staticDirs) {
app.use(nconf.get('relative_path') + '/plugins/' + d, express.static(plugins.staticDirs[d]));
if (process.env.NODE_ENV === 'development') {
winston.info('Static directory routed for plugin: ' + d);
}
}
next();
});
},
function(next) {
// Theme configuration
RDB.hmget('config', 'theme:type', 'theme:id', 'theme:staticDir', 'theme:templates', function(err, themeData) {
@ -701,6 +688,9 @@ var express = require('express'),
});
});
// Other routes
require('./routes/plugins')(app);
// Debug routes
if (process.env.NODE_ENV === 'development') {
require('./routes/debug')(app);

@ -666,10 +666,17 @@ module.exports.init = function(io) {
socket.on('api:config.set', function(data) {
meta.configs.set(data.key, data.value, function(err) {
if (!err) socket.emit('api:config.set', {
status: 'ok'
});
/* Another hook, for my (adarqui's) logger module */
if (!err) {
socket.emit('api:config.set', {
status: 'ok'
});
plugins.fireHook('action:config.set', {
key: data.key,
value: data.value
});
}
logger.monitorConfig(this, data);
});
});

Loading…
Cancel
Save