Merge remote-tracking branch 'origin/master' into webserver.js-refactor

Conflicts:
	app.js
	public/templates/category.tpl
	public/templates/popular.tpl
	public/templates/recent.tpl
	public/templates/unread.tpl
	src/routes/plugins.js
	src/webserver.js
v1.18.x
psychobunny 11 years ago
commit 1ef95bd09e

@ -1,6 +1,5 @@
# <img alt="NodeBB" src="http://i.imgur.com/3yj1n6N.png" />
[![Dependency Status](https://david-dm.org/designcreateplay/nodebb.png)](https://david-dm.org/designcreateplay/nodebb)
[![Code Climate](https://codeclimate.com/github/designcreateplay/NodeBB.png)](https://codeclimate.com/github/designcreateplay/NodeBB)
**NodeBB Forum Software** is powered by Node.js and built on a Redis database. It utilizes web sockets for instant interactions and real-time notifications. NodeBB is compatible down to IE8 and has many modern features out of the box such as social network integration and streaming discussions.

@ -141,7 +141,8 @@ function start() {
webserver.init();
});
notifications.init();
// Temporarily removed until ncb000gt/node-cron/issues/81 and ncb000gt/node-cron/issues/83 are fixed
// notifications.init();
process.on('SIGTERM', shutdown);
process.on('SIGINT', shutdown);

@ -28,7 +28,8 @@ var socket,
var reconnection_delay = 200;
socket = io.connect('', {
'max reconnection attempts': max_reconnection_attemps,
'reconnection delay': reconnection_delay
'reconnection delay': reconnection_delay,
resource: RELATIVE_PATH.length ? RELATIVE_PATH.slice(1) + '/socket.io' : 'socket.io'
});
var reconnecting = false,

@ -8,13 +8,11 @@ define(['notifications', 'chat'], function(Notifications, Chat) {
Chat.prepareDOM();
translator.prepareDOM();
function updateUnreadCount(err, tids) {
var count = 0, unreadEl = $('#unread-count');
function updateUnreadCount(err, count) {
var unreadEl = $('#unread-count');
if (err) {
console.warn('Error updating unread count', err);
} else if(tids && tids.length) {
count = tids.length;
}
unreadEl

@ -0,0 +1,117 @@
<input type="hidden" template-variable="category_id" value="{cid}" />
<input type="hidden" template-variable="category_name" value="{name}" />
<input type="hidden" template-variable="currentPage" value="{currentPage}" />
<input type="hidden" template-variable="pageCount" value="{pageCount}" />
<ol class="breadcrumb">
<li itemscope="itemscope" itemtype="http://data-vocabulary.org/Breadcrumb">
<a href="{relative_path}/" itemprop="url"><span itemprop="title">[[global:home]]</span></a>
</li>
<li class="active" itemscope="itemscope" itemtype="http://data-vocabulary.org/Breadcrumb">
<span itemprop="title">{name} <a target="_blank" href="../{cid}.rss"><i class="fa fa-rss-square"></i></a></span>
</li>
</ol>
<div>
<!-- IF privileges.write -->
<button id="new_post" class="btn btn-primary">[[category:new_topic_button]]</button>
<!-- ENDIF privileges.write -->
<!-- IF !config.disableSocialButtons -->
<div class="inline-block pull-right">
<a href="#" id="facebook-share"><i class="fa fa-facebook-square fa-2x"></i></a>&nbsp;
<a href="#" id="twitter-share"><i class="fa fa-twitter-square fa-2x"></i></a>&nbsp;
<a href="#" id="google-share"><i class="fa fa-google-plus-square fa-2x"></i></a>&nbsp;
</div>
<!-- ENDIF !config.disableSocialButtons -->
</div>
<hr/>
<!-- IF !topics.length -->
<div class="alert alert-warning" id="category-no-topics">
[[category:no_topics]]
</div>
<!-- ENDIF !topics.length -->
<div class="category row">
<div class="{topic_row_size}" no-widget-class="col-lg-12 col-sm-12">
<ul id="topics-container" itemscope itemtype="http://www.schema.org/ItemList" data-nextstart="{nextStart}">
<meta itemprop="itemListOrder" content="descending">
<!-- BEGIN topics -->
<li class="category-item <!-- IF topics.deleted -->deleted<!-- ENDIF topics.deleted --><!-- IF topics.unread -->unread<!-- ENDIF topics.unread -->" itemprop="itemListElement" data-tid="{topics.tid}" data-index="{topics.index}">
<div class="col-md-12 col-xs-12 panel panel-default topic-row">
<!--
todo: tidy this up, not sure what to do with the topic thumbs
todo: fix this nesting if issue#1065 is a win
todo: add a check for config.allowTopicsThumbnail if issue#1066 is a win
-->
<a href="../../user/{topics.user.userslug}" class="pull-left">
<img src="<!-- IF topics.thumb -->{topics.thumb}<!-- ELSE -->{topics.user.picture}<!-- ENDIF topics.thumb -->" class="img-rounded user-img" title="{topics.user.username}"/>
</a>
<h3>
<a href="../../topic/{topics.slug}" itemprop="url">
<meta itemprop="name" content="{topics.title}">
<strong><!-- IF topics.pinned --><i class="fa fa-thumb-tack"></i><!-- ENDIF topics.pinned --> <!-- IF topics.locked --><i class="fa fa-lock"></i><!-- ENDIF topics.locked --></strong>
<span class="topic-title">{topics.title}</span>
</a>
</h3>
<small>
<span class="topic-stats">
[[category:posts]]
<strong class="human-readable-number" title="{topics.postcount}">{topics.postcount}</strong>
</span>
|
<span class="topic-stats">
[[category:views]]
<strong class="human-readable-number" title="{topics.viewcount}">{topics.viewcount}</strong>
</span>
|
<span>
[[category:posted]] <span class="timeago" title="{topics.relativeTime}"></span>
</span>
<span class="pull-right">
<!-- IF topics.unreplied -->
[[category:no_replies]]
<!-- ELSE -->
<a href="../../user/{topics.teaser.userslug}">
<img class="teaser-pic" src="{topics.teaser.picture}" title="{topics.teaser.username}"/>
</a>
<a href="../../topic/{topics.slug}#{topics.teaser.pid}">
[[category:replied]]
</a>
<span class="timeago" title="{topics.teaser.timestamp}"></span>
<!-- ENDIF topics.unreplied -->
</span>
</small>
</div>
</li>
<!-- END topics -->
</ul>
<!-- IF config.usePagination -->
<div class="text-center">
<ul class="pagination">
<li class="previous pull-left"><a href="#"><i class="fa fa-chevron-left"></i> [[global:previouspage]]</a></li>
<li class="next pull-right"><a href="#">[[global:nextpage]] <i class="fa fa-chevron-right"></i></a></li>
</ul>
</div>
<!-- ENDIF config.usePagination -->
</div>
<!-- IF topics.length -->
<div widget-area="sidebar" class="col-md-3 col-xs-12 category-sidebar">
<!-- BEGIN widgets -->
{widgets.html}
<!-- END widgets -->
</div>
<!-- ENDIF topics.length -->
</div>

@ -0,0 +1,79 @@
<ol class="breadcrumb">
<li><a href="{relative_path}/">[[global:home]]</a></li>
<li class="active">[[global:header.popular]] <a href="{relative_path}/popular.rss"><i class="fa fa-rss-square"></i></a></li>
</ol>
<ul class="nav nav-pills">
<li class=''><a href='{relative_path}/popular/posts'>[[global:posts]]</a></li>
<li class=''><a href='{relative_path}/popular/views'>[[global:views]]</a></li>
</ul>
<br />
<a href="{relative_path}/popular">
<div class="alert alert-warning hide" id="new-topics-alert"></div>
</a>
<!-- IF !topics.length -->
<div class="alert alert-warning" id="category-no-topics">
<strong>There are no popular topics.</strong>
</div>
<!-- ENDIF !topics.length -->
<div class="category row">
<div class="col-md-12">
<ul id="topics-container" data-nextstart="{nextStart}">
<!-- BEGIN topics -->
<li class="category-item <!-- IF topics.deleted --> deleted<!-- ENDIF topics.deleted --><!-- IF topics.unread --> unread<!-- ENDIF topics.unread -->">
<div class="col-md-12 col-xs-12 panel panel-default topic-row">
<a href="{relative_path}/user/{topics.user.userslug}" class="pull-left">
<img class="img-rounded user-img" src="{topics.user.picture}" title="{topics.user.username}" />
</a>
<h3>
<a href="{relative_path}/topic/{topics.slug}">
<strong><!-- IF topics.pinned --><i class="fa fa-thumb-tack"></i><!-- ENDIF topics.pinned --> <!-- IF topics.locked --><i class="fa fa-lock"></i><!-- ENDIF topics.locked --></strong>
<span class="topic-title">{topics.title}</span>
</a>
</h3>
<small>
<span class="topic-stats">
[[category:posts]]
<strong class="human-readable-number" title="{topics.postcount}">{topics.postcount}</strong>
</span>
|
<span class="topic-stats">
[[category:views]]
<strong class="human-readable-number" title="{topics.viewcount}">{topics.viewcount}</strong>
</span>
|
<span>
[[category:posted]] [[global:in]]
<a href="{relative_path}/category/{topics.category.slug}">
<i class="fa {topics.category.icon}"></i> {topics.category.name}
</a>
<span class="timeago" title="{topics.relativeTime}"></span>
</span>
</span>
<span class="pull-right">
<!-- IF topics.unreplied -->
[[category:no_replies]]
<!-- ELSE -->
<a href="{relative_path}/user/{topics.teaser.userslug}">
<img class="teaser-pic" src="{topics.teaser.picture}" title="{topics.teaser.username}"/>
</a>
<a href="{relative_path}/topic/{topics.slug}#{topics.teaser.pid}">
[[category:replied]]
</a>
<span class="timeago" title="{topics.teaser.timestamp}"></span>
<!-- ENDIF topics.unreplied -->
</span>
</small>
</div>
</li>
<!-- END topics -->
</ul>
</div>
</div>

@ -0,0 +1,78 @@
<ol class="breadcrumb">
<li><a href="{relative_path}/">[[global:home]]</a></li>
<li class="active">[[recent:title]] <a href="{relative_path}/recent.rss"><i class="fa fa-rss-square"></i></a></li>
</ol>
<ul class="nav nav-pills">
<li class=''><a href='{relative_path}/recent/day'>[[recent:day]]</a></li>
<li class=''><a href='{relative_path}/recent/week'>[[recent:week]]</a></li>
<li class=''><a href='{relative_path}/recent/month'>[[recent:month]]</a></li>
</ul>
<br />
<a href="{relative_path}/recent">
<div class="alert alert-warning hide" id="new-topics-alert"></div>
</a>
<!-- IF !topics.length -->
<div class="alert alert-warning" id="category-no-topics">
<strong>[[recent:no_recent_topics]]</strong>
</div>
<!-- ENDIF !topics.length -->
<div class="category row">
<div class="col-md-12">
<ul id="topics-container" data-nextstart="{nextStart}">
<!-- BEGIN topics -->
<li class="category-item <!-- IF topics.deleted --> deleted<!-- ENDIF topics.deleted --><!-- IF topics.unread --> unread<!-- ENDIF topics.unread -->">
<div class="col-md-12 col-xs-12 panel panel-default topic-row">
<a href="{relative_path}/user/{topics.user.userslug}" class="pull-left">
<img class="img-rounded user-img" src="{topics.user.picture}" title="{topics.user.username}" />
</a>
<h3>
<a href="{relative_path}/topic/{topics.slug}">
<strong><!-- IF topics.pinned --><i class="fa fa-thumb-tack"></i><!-- ENDIF topics.pinned --> <!-- IF topics.locked --><i class="fa fa-lock"></i><!-- ENDIF topics.locked --></strong>
<span class="topic-title">{topics.title}</span>
</a>
</h3>
<small>
<span class="topic-stats">
[[category:posts]]
<strong class="human-readable-number" title="{topics.postcount}">{topics.postcount}</strong>
</span>
|
<span class="topic-stats">
[[category:views]]
<strong class="human-readable-number" title="{topics.viewcount}">{topics.viewcount}</strong>
</span>
|
<span>
[[category:posted]] [[global:in]]
<a href="{relative_path}/category/{topics.category.slug}"><i class="fa {topics.category.icon}"></i> {topics.category.name}</a>
<span class="timeago" title="{topics.relativeTime}"></span>
</span>
</span>
<span class="pull-right">
<!-- IF topics.unreplied -->
[[category:no_replies]]
<!-- ELSE -->
<a href="{relative_path}/user/{topics.teaser.userslug}">
<img class="teaser-pic" src="{topics.teaser.picture}" title="{topics.teaser.username}"/>
</a>
<a href="{relative_path}/topic/{topics.slug}#{topics.teaser.pid}">
[[category:replied]]
</a>
<span class="timeago" title="{topics.teaser.timestamp}"></span>
<!-- ENDIF topics.unreplied -->
</span>
</small>
</div>
</li>
<!-- END topics -->
</ul>
</div>
</div>

@ -0,0 +1,73 @@
<div class="unread">
<ol class="breadcrumb">
<li><a href="{relative_path}/">[[global:home]]</a></li>
<li class="active">[[unread:title]]</li>
</ol>
<div class="alert alert-warning {no_topics_message}" id="category-no-topics">
<strong>[[unread:no_unread_topics]]</strong>
</div>
<button id="mark-allread-btn" class="btn btn-primary {show_markallread_button}">[[unread:mark_all_read]]</button>
<a href="{relative_path}/unread">
<div class="alert alert-warning hide" id="new-topics-alert"></div>
</a>
<div class="category row">
<div class="col-md-12">
<ul id="topics-container" data-nextstart="{nextStart}">
<!-- BEGIN topics -->
<li class="category-item<!-- IF topics.deleted --> deleted<!-- ENDIF topics.deleted -->" data-tid="{topics.tid}">
<div class="col-md-12 col-xs-12 panel panel-default topic-row">
<a href="{relative_path}/user/{topics.user.userslug}" class="pull-left">
<img class="img-rounded user-img" src="{topics.user.picture}" title="{topics.user.username}" />
</a>
<h3>
<a href="{relative_path}/topic/{topics.slug}">
<strong><!-- IF topics.pinned --><i class="fa fa-thumb-tack"></i><!-- ENDIF topics.pinned --> <!-- IF topics.locked --><i class="fa fa-lock"></i><!-- ENDIF topics.locked --></strong>
<span class="topic-title">{topics.title}</span>
</a>
</h3>
<small>
<span class="topic-stats">
[[category:posts]]
<strong class="human-readable-number" title="{topics.postcount}">{topics.postcount}</strong>
</span>
|
<span class="topic-stats">
[[category:views]]
<strong class="human-readable-number" title="{topics.viewcount}">{topics.viewcount}</strong>
</span>
|
<span>
[[category:posted]] [[global:in]]
<a href="{relative_path}/category/{topics.category.slug}"><i class="fa {topics.category.icon}"></i> {topics.category.name}</a>
<span class="timeago" title="{topics.relativeTime}"></span>
</span>
</span>
<span class="pull-right">
<!-- IF topics.unreplied -->
[[category:no_replies]]
<!-- ELSE -->
<a href="{relative_path}/user/{topics.teaser.userslug}">
<img class="teaser-pic" src="{topics.teaser.picture}" title="{topics.teaser.username}"/>
</a>
<a href="{relative_path}/topic/{topics.slug}#{topics.teaser.pid}">
[[category:replied]]
</a>
<span class="timeago" title="{topics.teaser.timestamp}"></span>
<!-- ENDIF topics.unreplied -->
</span>
</small>
</div>
</li>
<!-- END topics -->
</ul>
<button id="load-more-btn" class="btn btn-primary hide">[[unread:load_more]]</button>
</div>
</div>
</div>

@ -82,18 +82,6 @@
//
// helper functions
//
function removeHiddenFields(item) {
if(item) {
if(item._id) {
delete item._id;
}
if(item._key) {
delete item._key;
}
}
return item;
}
function findItem(data, key) {
if(!data) {
return null;
@ -261,11 +249,7 @@
};
module.getObject = function(key, callback) {
db.collection('objects').findOne({_key:key}, function(err, item) {
removeHiddenFields(item);
callback(err, item);
});
db.collection('objects').findOne({_key:key}, {_id:0, _key:0}, callback);
};
module.getObjects = function(keys, callback) {
@ -302,7 +286,9 @@
module.getObjectFields = function(key, fields, callback) {
var _fields = {};
var _fields = {
_id: 0
};
for(var i=0; i<fields.length; ++i) {
if (typeof fields[i] !== 'string') {
fields[i] = fields[i].toString();
@ -312,6 +298,7 @@
_fields[fields[i]] = 1;
}
db.collection('objects').findOne({_key:key}, _fields, function(err, item) {
if(err) {
@ -328,8 +315,6 @@
}
}
removeHiddenFields(item);
callback(null, item);
});
};

@ -1,3 +1,5 @@
'use strict';
var db = require('./database'),
async = require('async'),
user = require('./user'),
@ -35,7 +37,7 @@ var db = require('./database'),
Messaging.updateChatTime(touid, fromuid);
callback(null, message);
});
}
};
Messaging.getMessages = function(fromuid, touid, callback) {
var uids = sortUids(fromuid, touid);

@ -249,7 +249,7 @@ var fs = require('fs'),
'src/overrides.js',
'src/utils.js'
],
minFile: nconf.get('relative_path') + 'nodebb.min.js',
minFile: 'nodebb.min.js',
get: function (callback) {
plugins.fireHook('filter:scripts.get', this.scripts, function(err, scripts) {
var ctime,

@ -51,22 +51,13 @@ function routeCurrentTheme(app, themeData) {
// Theme's static directory
if (themeData['theme:staticDir']) {
app.use('/css/assets', express.static(path.join(nconf.get('themes_path'), themeData['theme:id'], themeData['theme:staticDir']), {
app.use(nconf.get('relative_path') + '/css/assets', express.static(path.join(nconf.get('themes_path'), themeData['theme:id'], themeData['theme:staticDir']), {
maxAge: app.enabled('cache') ? 5184000000 : 0
}));
if (process.env.NODE_ENV === 'development') {
winston.info('Static directory routed for theme: ' + themeData['theme:id']);
}
}
if (themeData['theme:templates']) {
app.use('/templates', express.static(path.join(nconf.get('themes_path'), themeData['theme:id'], themeData['theme:templates']), {
maxAge: app.enabled('cache') ? 5184000000 : 0
}));
if (process.env.NODE_ENV === 'development') {
winston.info('Custom templates directory routed for theme: ' + themeData['theme:id']);
}
}
} else {
// If not using a local theme (bootswatch, etc), drop back to vanilla
if (process.env.NODE_ENV === 'development') {

@ -307,7 +307,7 @@ middleware.routeTouchIcon = function(req, res) {
if (meta.config['brand:logo'] && validator.isURL(meta.config['brand:logo'])) {
return res.redirect(meta.config['brand:logo']);
} else {
return res.sendfile(path.join(__dirname, '../../public', meta.config['brand:logo'] || nconf.get('relative_path') + '/logo.png'), {
return res.sendfile(path.join(__dirname, '../public', meta.config['brand:logo'] || '/logo.png'), {
maxAge: app.enabled('cache') ? 5184000000 : 0
});
}

@ -9,7 +9,6 @@ var _ = require('underscore'),
winston = require('winston'),
plugins = require('../plugins'),
pluginRoutes = [];
/*

@ -28,11 +28,11 @@ var io;
Sockets.init = function(server) {
io = socketioWildcard(SocketIO).listen(server, {
log: false,
transports: ['websocket', 'xhr-polling', 'jsonp-polling', 'flashsocket'],
'browser client minification': true
'browser client minification': true,
resource: nconf.get('relative_path') + '/socket.io'
});
Sockets.server = io;

@ -101,7 +101,7 @@ SocketTopics.markAllRead = function(socket, data, callback) {
return callback(err);
}
index.server.sockets.in('uid_' + socket.uid).emit('event:unread.updateCount', null, []);
index.server.sockets.in('uid_' + socket.uid).emit('event:unread.updateCount', null, 0);
callback();
});

@ -214,7 +214,7 @@ SocketUser.getOnlineAnonCount = function(socket, data, callback) {
};
SocketUser.getUnreadCount = function(socket, data, callback) {
topics.getUnreadTids(socket.uid, 0, 19, callback);
topics.getTotalUnread(socket.uid, callback);
};
SocketUser.getActiveUsers = function(socket, data, callback) {

@ -323,17 +323,35 @@ var async = require('async'),
};
Topics.getTopicData = function(tid, callback) {
db.getObject('topic:' + tid, function(err, data) {
if(err) {
return callback(err, null);
Topics.getTopicsData([tid], function(err, topics) {
if (err) {
return callback(err);
}
callback(null, topics ? topics[0] : null);
});
};
Topics.getTopicsData = function(tids, callback) {
var keys = [];
for (var i=0; i<tids.length; ++i) {
keys.push('topic:' + tids[i]);
}
db.getObjects(keys, function(err, topics) {
if (err) {
return callback(err);
}
if(data) {
data.title = validator.escape(data.title);
data.relativeTime = utils.toISOString(data.timestamp);
for (var i=0; i<tids.length; ++i) {
if(topics[i]) {
topics[i].title = validator.escape(topics[i].title);
topics[i].relativeTime = utils.toISOString(topics[i].timestamp);
}
}
callback(null, data);
callback(null, topics);
});
};
@ -352,9 +370,12 @@ var async = require('async'),
userData = {};
}
topic.username = userData.username || 'Anonymous';
topic.userslug = userData.userslug || '';
topic.picture = userData.picture || gravatar.url('', {}, true);
topic.user = {
username: userData.username || 'Anonymous',
userslug: userData.userslug || '',
picture: userData.picture || gravatar.url('', {}, true)
};
callback(null, topic);
});
});
@ -538,8 +559,8 @@ var async = require('async'),
};
Topics.getTotalUnread = function(uid, callback) {
Topics.getUnreadTids(uid, 0, 21, function(err, tids) {
callback(err, {count: tids ? tids.length : 0});
Topics.getUnreadTids(uid, 0, 20, function(err, tids) {
callback(err, tids ? tids.length : 0);
});
};
@ -553,7 +574,7 @@ var async = require('async'),
}
async.whilst(function() {
return unreadTids.length < 20 && !done;
return unreadTids.length < 21 && !done;
}, function(callback) {
Topics.getLatestTids(start, stop, 'month', function(err, tids) {
if (err) {
@ -650,8 +671,8 @@ var async = require('async'),
});
async.each(uids, function(uid, next) {
Topics.getUnreadTids(uid, 0, 19, function(err, tids) {
websockets.in('uid_' + uid).emit('event:unread.updateCount', null, tids);
Topics.getTotalUnread(uid, function(err, count) {
websockets.in('uid_' + uid).emit('event:unread.updateCount', null, count);
next();
});
}, function(err) {
@ -671,73 +692,86 @@ var async = require('async'),
return callback(null, []);
}
function getTopicInfo(topicData, callback) {
var categoryCache = {},
privilegeCache = {},
userCache = {};
function loadTopicInfo(topicData, next) {
function isTopicVisible(topicData, topicInfo) {
var deleted = parseInt(topicData.deleted, 10) !== 0;
return !deleted || (deleted && topicInfo.privileges.view_deleted) || parseInt(topicData.uid, 10) === parseInt(uid, 10);
}
async.parallel({
hasread : function (next) {
hasread: function(next) {
Topics.hasReadTopic(topicData.tid, uid, next);
},
teaser : function (next) {
teaser: function(next) {
Topics.getTeaser(topicData.tid, next);
},
privileges : function (next) {
privileges: function(next) {
if (privilegeCache[topicData.cid]) {
return next(null, privilegeCache[topicData.cid]);
}
categoryTools.privileges(topicData.cid, uid, next);
},
categoryData : function (next) {
categoryData: function(next) {
if (categoryCache[topicData.cid]) {
return next(null, categoryCache[topicData.cid]);
}
categories.getCategoryFields(topicData.cid, ['name', 'slug', 'icon'], next);
},
user: function(next) {
if (userCache[topicData.uid]) {
return next(null, userCache[topicData.uid]);
}
user.getUserFields(topicData.uid, ['username', 'userslug', 'picture'], next);
}
}, callback);
}
function isTopicVisible(topicData, topicInfo) {
var deleted = parseInt(topicData.deleted, 10) !== 0;
return !deleted || (deleted && topicInfo.privileges.view_deleted) || parseInt(topicData.uid, 10) === parseInt(uid, 10);
}
function loadTopic(tid, next) {
Topics.getTopicDataWithUser(tid, function(err, topicData) {
}, function(err, topicInfo) {
if(err) {
return next(err);
}
if (!topicData) {
privilegeCache[topicData.cid] = topicInfo.privileges;
categoryCache[topicData.cid] = topicInfo.categoryData;
userCache[topicData.uid] = topicInfo.user;
if (!isTopicVisible(topicData, topicInfo)) {
topicData = null;
return next();
}
getTopicInfo(topicData, function(err, topicInfo) {
if(err) {
return next(err);
}
if (!isTopicVisible(topicData, topicInfo)) {
return next();
}
topicData.pinned = parseInt(topicData.pinned, 10) === 1;
topicData.locked = parseInt(topicData.locked, 10) === 1;
topicData.deleted = parseInt(topicData.deleted, 10) === 1;
topicData.unread = !(topicInfo.hasread && parseInt(uid, 10) !== 0);
topicData.unreplied = parseInt(topicData.postcount, 10) === 1;
topicData.pinned = parseInt(topicData.pinned, 10) === 1;
topicData.locked = parseInt(topicData.locked, 10) === 1;
topicData.deleted = parseInt(topicData.deleted, 10) === 1;
topicData.unread = !(topicInfo.hasread && parseInt(uid, 10) !== 0);
topicData.unreplied = parseInt(topicData.postcount, 10) === 1;
topicData.category = topicInfo.categoryData;
topicData.teaser = topicInfo.teaser;
topicData.category = topicInfo.categoryData;
topicData.teaser = topicInfo.teaser;
topicData.user = topicInfo.user;
next(null, topicData);
});
next();
});
}
async.map(tids, loadTopic, function(err, topics) {
if(err) {
Topics.getTopicsData(tids, function(err, topics) {
if (err) {
return callback(err);
}
topics = topics.filter(function(topic) {
return !!topic;
});
async.eachSeries(topics, loadTopicInfo, function(err) {
if(err) {
return callback(err);
}
callback(null, topics);
topics = topics.filter(function(topic) {
return !!topic;
});
callback(null, topics);
});
});
};

@ -95,4 +95,5 @@ if(nconf.get('ssl')) {
winston.info('NodeBB Ready');
});
};
}(WebServer));

Loading…
Cancel
Save