mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-03-04 19:41:16 +01:00
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
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
# <img alt="NodeBB" src="http://i.imgur.com/3yj1n6N.png" />
|
||||
[](https://david-dm.org/designcreateplay/nodebb)
|
||||
[](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.
|
||||
|
||||
|
||||
3
app.js
3
app.js
@@ -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
|
||||
|
||||
117
public/templates/category.tpl
Normal file
117
public/templates/category.tpl
Normal file
@@ -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>
|
||||
<a href="#" id="twitter-share"><i class="fa fa-twitter-square fa-2x"></i></a>
|
||||
<a href="#" id="google-share"><i class="fa fa-google-plus-square fa-2x"></i></a>
|
||||
</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>
|
||||
|
||||
79
public/templates/popular.tpl
Normal file
79
public/templates/popular.tpl
Normal file
@@ -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>
|
||||
78
public/templates/recent.tpl
Normal file
78
public/templates/recent.tpl
Normal file
@@ -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>
|
||||
73
public/templates/unread.tpl
Normal file
73
public/templates/unread.tpl
Normal file
@@ -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) {
|
||||
|
||||
148
src/topics.js
148
src/topics.js
@@ -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);
|
||||
}
|
||||
|
||||
if(data) {
|
||||
data.title = validator.escape(data.title);
|
||||
data.relativeTime = utils.toISOString(data.timestamp);
|
||||
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);
|
||||
}
|
||||
|
||||
callback(null, data);
|
||||
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, 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);
|
||||
}
|
||||
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;
|
||||
|
||||
if (!isTopicVisible(topicData, topicInfo)) {
|
||||
return next();
|
||||
}
|
||||
topicData.category = topicInfo.categoryData;
|
||||
topicData.teaser = topicInfo.teaser;
|
||||
topicData.user = topicInfo.user;
|
||||
|
||||
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;
|
||||
|
||||
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));
|
||||
|
||||
Reference in New Issue
Block a user