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

v1.18.x
Julian Lam 11 years ago
commit 8e1137b5dd

@ -25,7 +25,6 @@
"passport-facebook": "0.1.5",
"less-middleware": "0.1.12",
"marked": "0.2.8",
"bcrypt": "0.7.5",
"async": "~0.2.8",
"node-imagemagick": "0.1.8",
"gravatar": "1.0.6",
@ -47,7 +46,8 @@
"semver": "~2.2.1",
"string": "~1.7.0",
"xregexp": "~2.0.0",
"socket.io-wildcard": "~0.1.1"
"socket.io-wildcard": "~0.1.1",
"bcryptjs": "~0.7.10"
},
"optionalDependencies": {
"redis": "0.8.3",

@ -396,6 +396,16 @@ var socket,
});
};
app.enableInfiniteLoading = function(callback) {
$(window).off('scroll').on('scroll', function() {
var bottom = ($(document).height() - $(window).height()) * 0.9;
if ($(window).scrollTop() > bottom) {
callback();
}
});
}
var titleObj = {
active: false,
interval: undefined,

@ -178,13 +178,13 @@ define(['uploader'], function(uploader) {
});
// Permissions modal
$('.permissions').on('click', function() {
$('.admin-categories').on('click', '.permissions', function() {
var cid = $(this).parents('li[data-cid]').attr('data-cid');
Categories.launchPermissionsModal(cid);
});
$('.upload-button').on('click', function() {
$('.admin-categories').on('click', '.upload-button', function() {
var inputEl = this;
var cid = $(this).parents('li[data-cid]').attr('data-cid');
uploader.open(RELATIVE_PATH + '/admin/category/uploadpicture', {cid:cid}, function(imageUrlOnServer) {
@ -196,7 +196,7 @@ define(['uploader'], function(uploader) {
});
});
$('.admin-categories').delegate('.delete-image', 'click', function() {
$('.admin-categories').on('click', '.delete-image', function() {
var parent = $(this).parents('li[data-cid]'),
inputEl = parent.find('.upload-button'),
preview = parent.find('.preview-box'),

@ -18,6 +18,7 @@ define(function() {
};
Admin.updateRoomUsage = function(err, data) {
function getUserCountIn(room) {
var count = 0;
for(var user in data[room]) {
@ -25,27 +26,36 @@ define(function() {
}
return count;
}
var active_users = $('#active_users'),
var active_users = $('#active_users').html(''),
total = 0;
if(!active_users.length) {
return;
}
active_users.html('');
var usersHtml = '';
var sortedData = [];
for (var room in data) {
if (room !== '') {
var count = getUserCountIn(room);
total += count;
usersHtml += "<div class='alert alert-success'><strong>" + room + "</strong> " + count + " active user" + (count > 1 ? "s" : "") + "</div>";
sortedData.push({room: room, count: data[room].length});
total += data[room].length;
}
}
sortedData.sort(function(a, b) {
return parseInt(b.count, 10) - parseInt(a.count, 10);
});
var usersHtml = '';
for(var i=0; i<sortedData.length; ++i) {
usersHtml += "<div class='alert alert-success'><strong>" + sortedData[i].room + "</strong> " +
sortedData[i].count + " active user" + (sortedData[i].count > 1 ? "s" : "") + "</div>";
}
active_users.html(usersHtml);
document.getElementById('connections').innerHTML = total;
$('#connections').html(total);
};
return Admin;

@ -44,11 +44,9 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
function enableInfiniteLoading() {
if(!config.usePagination) {
$(window).off('scroll').on('scroll', function (ev) {
var bottom = ($(document).height() - $(window).height()) * 0.9;
if ($(window).scrollTop() > bottom && !loadingMoreTopics) {
Category.loadMoreTopics(cid);
app.enableInfiniteLoading(function() {
if(!loadingMoreTopics) {
Category.loadMoreTopics(templates.get('category_id'));
}
});
} else {
@ -147,7 +145,7 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
loadingMoreTopics = true;
socket.emit('categories.loadMore', {
cid: cid,
after: $('#topics-container').children('.category-item').length
after: $('#topics-container').attr('data-nextstart')
}, function (err, data) {
if(err) {
return app.alertError(err.message);
@ -155,6 +153,7 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
if (data && data.topics.length) {
Category.onTopicsLoaded(data.topics);
$('#topics-container').attr('data-nextstart', data.nextStart);
}
loadingMoreTopics = false;
});

@ -52,12 +52,6 @@ define(function() {
});
document.querySelector('#content input').focus();
if(!config.emailSetup)
$('#reset-link').addClass('hide');
else
$('#reset-link').removeClass('hide');
};
return Login;

@ -14,11 +14,11 @@ define(function() {
$('.pagination')
.on('click', '.previous', function() {
pagination.loadPage(pagination.currentPage - 1);
return pagination.loadPage(pagination.currentPage - 1);
}).on('click', '.next', function() {
pagination.loadPage(pagination.currentPage + 1);
return pagination.loadPage(pagination.currentPage + 1);
}).on('click', '.page', function() {
pagination.loadPage($(this).attr('data-page'));
return pagination.loadPage($(this).attr('data-page'));
}).on('click', '.select_page', function(e) {
e.preventDefault();
bootbox.prompt('Enter page number:', function(pageNum) {
@ -58,7 +58,7 @@ define(function() {
for(var i=0; i<pagesToShow.length; ++i) {
if(i > 0) {
if (pagesToShow[i] - 1 !== pagesToShow[i-1]) {
html += '<li class="disabled"><a class="select_page" href="#">|</a></li>';
html += '<li><a class="select_page" href="#">|</a></li>';
}
}
html += '<li class="page" data-page="' + pagesToShow[i] + '"><a href="#">' + pagesToShow[i] + '</a></li>';
@ -72,10 +72,11 @@ define(function() {
pagination.loadPage = function(page, callback) {
page = parseInt(page, 10);
if(!utils.isNumber(page) || page < 1 || page > pagination.pageCount) {
return;
return false;
}
ajaxify.go(window.location.pathname.slice(1) + '?page=' + page);
return true;
}
function updatePageLinks() {

@ -1,20 +1,16 @@
define(function() {
var Recent = {};
Recent.newTopicCount = 0;
Recent.newPostCount = 0;
Recent.loadingMoreTopics = false;
var newTopicCount = 0,
newPostCount = 0,
loadingMoreTopics = false;
var active = '';
Recent.init = function() {
app.enterRoom('recent_posts');
ajaxify.register_events([
'event:new_topic',
'event:new_post'
]);
Recent.watchForNewPosts();
function getActiveSection() {
var url = window.location.href,
@ -37,26 +33,34 @@ define(function() {
$(this).addClass('hide');
});
socket.on('event:new_topic', function(data) {
++Recent.newTopicCount;
Recent.updateAlertText();
app.enableInfiniteLoading(function() {
if(!loadingMoreTopics) {
Recent.loadMoreTopics();
}
});
};
Recent.watchForNewPosts = function () {
newPostCount = 0;
newTopicCount = 0;
ajaxify.register_events([
'event:new_topic',
'event:new_post'
]);
socket.on('event:new_topic', function(data) {
++newTopicCount;
Recent.updateAlertText();
});
socket.on('event:new_post', function(data) {
++Recent.newPostCount;
++newPostCount;
Recent.updateAlertText();
});
$(window).off('scroll').on('scroll', function() {
var bottom = ($(document).height() - $(window).height()) * 0.9;
if ($(window).scrollTop() > bottom && !Recent.loadingMoreTopics) {
Recent.loadMoreTopics();
}
});
};
Recent.updateAlertText = function() {
var text = 'There';
@ -76,41 +80,44 @@ define(function() {
text += '. Click here to reload.';
$('#new-topics-alert').html(text).removeClass('hide').fadeIn('slow');
$('#category-no-topics').addClass('hide');
}
Recent.onTopicsLoaded = function(topics) {
var html = templates.prepare(templates['recent'].blocks['topics']).parse({
Recent.loadMoreTopics = function() {
loadingMoreTopics = true;
socket.emit('topics.loadMoreRecentTopics', {
after: $('#topics-container').attr('data-nextstart'),
term: active
}, function(err, data) {
if(err) {
return app.alertError(err.message);
}
if (data.topics && data.topics.length) {
Recent.onTopicsLoaded('recent', data.topics);
$('#topics-container').attr('data-nextstart', data.nextStart);
}
loadingMoreTopics = false;
});
}
Recent.onTopicsLoaded = function(template, topics) {
var html = templates.prepare(templates[template].blocks['topics']).parse({
topics: topics
});
translator.translate(html, function(translatedHTML) {
var container = $('#topics-container');
$('#category-no-topics').remove();
html = $(translatedHTML);
container.append(html);
$('#topics-container').append(html);
$('span.timeago').timeago();
app.createUserTooltips();
app.makeNumbersHumanReadable(html.find('.human-readable-number'));
});
}
Recent.loadMoreTopics = function() {
Recent.loadingMoreTopics = true;
socket.emit('topics.loadMoreRecentTopics', {
after: $('#topics-container').children('li').length,
term: active
}, function(err, data) {
if(err) {
return app.alertError(err.message);
}
if (data.topics && data.topics.length) {
Recent.onTopicsLoaded(data.topics);
}
Recent.loadingMoreTopics = false;
});
}
return Recent;
});

@ -2,9 +2,9 @@ define(function() {
var Search = {};
Search.init = function() {
var searchQuery = $('#topics-container').attr('data-search-query');
$('.search-result-text').each(function() {
var searchQuery = $('#topic-results').attr('data-search-query');
console.log(searchQuery);
$('.search-result-text').children().each(function() {
var text = $(this).html();
var regex = new RegExp(searchQuery, 'gi');
text = text.replace(regex, '<span class="label label-success">' + searchQuery + '</span>');

@ -346,10 +346,8 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
function enableInfiniteLoading() {
if(!config.usePagination) {
$(window).off('scroll').on('scroll', function() {
var bottom = ($(document).height() - $(window).height()) * 0.9;
if ($(window).scrollTop() > bottom && !infiniteLoaderActive && $('#post-container').children().length) {
app.enableInfiniteLoading(function() {
if (!infiniteLoaderActive && $('#post-container').children().length) {
loadMorePosts(tid, function(posts) {
fixDeleteStateForPosts();
});
@ -396,7 +394,7 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
socket.emit('posts.getRawPost', pid, function(err, post) {
if(err) {
return app.alert(err.message);
return app.alertError(err.message);
}
var quoted = '';
if(post) {
@ -895,47 +893,34 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
}
function toggle_post_delete_state(pid) {
var postEl = $(document.querySelector('#post-container li[data-pid="' + pid + '"]'));
if (postEl[0]) {
quoteEl = postEl.find('.quote'),
favEl = postEl.find('.favourite'),
replyEl = postEl.find('.post_reply');
socket.emit('posts.getPrivileges', pid, function(err, privileges) {
if(err) {
return app.alert(err.message);
}
if (privileges.editable) {
if (!postEl.hasClass('deleted')) {
toggle_post_tools(pid, false);
} else {
toggle_post_tools(pid, true);
}
}
var postEl = $('#post-container li[data-pid="' + pid + '"]');
if (postEl.length) {
postEl.toggleClass('deleted');
toggle_post_tools(pid, postEl.hasClass('deleted'));
updatePostCount();
});
}
}
function toggle_post_tools(pid, state) {
var postEl = $(document.querySelector('#post-container li[data-pid="' + pid + '"]')),
function toggle_post_tools(pid, isDeleted) {
var postEl = $('#post-container li[data-pid="' + pid + '"]'),
quoteEl = $(postEl[0].querySelector('.quote')),
favEl = $(postEl[0].querySelector('.favourite')),
replyEl = $(postEl[0].querySelector('.post_reply'));
replyEl = $(postEl[0].querySelector('.post_reply')),
chatEl = $(postEl[0].querySelector('.chat'));
if (state) {
quoteEl.removeClass('none');
favEl.removeClass('none');
replyEl.removeClass('none');
} else {
if (isDeleted) {
quoteEl.addClass('none');
favEl.addClass('none');
replyEl.addClass('none');
chatEl.addClass('none');
} else {
quoteEl.removeClass('none');
favEl.removeClass('none');
replyEl.removeClass('none');
chatEl.removeClass('none');
}
}
@ -1112,7 +1097,7 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
var insertAfter = findInsertionPoint();
parseAndTranslatePosts(data.posts, function(translatedHTML) {
parseAndTranslatePosts(data, function(translatedHTML) {
var translated = $(translatedHTML);
if(!infiniteLoaded) {
@ -1127,8 +1112,8 @@ define(['composer', 'forum/pagination'], function(composer, pagination) {
});
}
function parseAndTranslatePosts(posts, callback) {
var html = templates.prepare(templates['topic'].blocks['posts']).parse({posts: posts});
function parseAndTranslatePosts(data, callback) {
var html = templates.prepare(templates['topic'].blocks['posts']).parse(data);
var regexp = new RegExp("<!--[\\s]*IF @first[\\s]*-->([\\s\\S]*?)<!--[\\s]*ENDIF @first[\\s]*-->", 'g');
html = html.replace(regexp, '');

@ -1,53 +1,15 @@
define(function() {
define(['forum/recent'], function(recent) {
var Unread = {},
loadingMoreTopics = false;
Unread.init = function() {
app.enterRoom('recent_posts');
ajaxify.register_events([
'event:new_topic',
'event:new_post',
'topics.markAllRead'
]);
var newTopicCount = 0,
newPostCount = 0;
$('#new-topics-alert').on('click', function() {
$(this).addClass('hide');
});
socket.on('event:new_topic', function(data) {
++newTopicCount;
updateAlertText();
});
function updateAlertText() {
var text = 'There';
if (newTopicCount > 1) {
text += ' are ' + newTopicCount + ' new topics';
} else if (newTopicCount === 1) {
text += ' is a new topic';
}
if (newPostCount > 1) {
text += (newTopicCount?' and ':' are ') + newPostCount + ' new posts';
} else if(newPostCount === 1) {
text += (newTopicCount?' and ':' is ') + ' a new post';
}
text += '. Click here to reload.';
$('#new-topics-alert').html(text).removeClass('hide').fadeIn('slow');
$('#category-no-topics').addClass('hidden');
}
socket.on('event:new_post', function(data) {
++newPostCount;
updateAlertText();
});
recent.watchForNewPosts();
$('#mark-allread-btn').on('click', function() {
var btn = $(this);
@ -67,37 +29,32 @@ define(function() {
});
});
function onTopicsLoaded(topics) {
if ($("body").height() <= $(window).height() && $('#topics-container').children().length >= 20) {
$('#load-more-btn').show();
}
var html = templates.prepare(templates['unread'].blocks['topics']).parse({
topics: topics
$('#load-more-btn').on('click', function() {
loadMoreTopics();
});
translator.translate(html, function(translatedHTML) {
var container = $('#topics-container');
$('#category-no-topics').remove();
html = $(translatedHTML);
container.append(html);
$('span.timeago').timeago();
app.createUserTooltips();
app.makeNumbersHumanReadable(html.find('.human-readable-number'));
});
app.enableInfiniteLoading(function() {
if(!loadingMoreTopics) {
loadMoreTopics();
}
});
function loadMoreTopics() {
loadingMoreTopics = true;
socket.emit('topics.loadMoreUnreadTopics', {
after: parseInt($('#topics-container').attr('data-next-start'), 10)
after: $('#topics-container').attr('data-nextstart')
}, function(err, data) {
if(err) {
return app.alertError(err.message);
}
if (data.topics && data.topics.length) {
onTopicsLoaded(data.topics);
$('#topics-container').attr('data-next-start', data.nextStart);
recent.onTopicsLoaded('unread', data.topics);
$('#topics-container').attr('data-nextstart', data.nextStart);
} else {
$('#load-more-btn').hide();
}
@ -105,23 +62,6 @@ define(function() {
loadingMoreTopics = false;
});
}
$(window).off('scroll').on('scroll', function() {
var bottom = ($(document).height() - $(window).height()) * 0.9;
if ($(window).scrollTop() > bottom && !loadingMoreTopics) {
loadMoreTopics();
}
});
if ($("body").height() <= $(window).height() && $('#topics-container').children().length >= 20) {
$('#load-more-btn').show();
}
$('#load-more-btn').on('click', function() {
loadMoreTopics();
});
};
return Unread;

@ -106,6 +106,7 @@
collapseWhitespace : /\s+/g,
collapseDash : /-+/g,
trimTrailingDash : /-$/g,
trimLeadingDash : /^-/g,
isLatin : /^[\w]+$/,
//http://dense13.com/blog/2009/05/03/converting-string-to-slug-javascript/
@ -120,6 +121,7 @@
str = str.replace(utils.collapseWhitespace, '-')
str = str.replace(utils.collapseDash, '-');
str = str.replace(utils.trimTrailingDash, '');
str = str.replace(utils.trimLeadingDash, '');
return str;
},

@ -28,7 +28,7 @@
<div class="category row">
<div class="{topic_row_size}">
<ul id="topics-container" itemscope itemtype="http://www.schema.org/ItemList">
<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 {topics.deleted-class}" itemprop="itemListElement">

@ -41,7 +41,10 @@
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<hr />
<button class="btn btn-primary btn-lg btn-block" id="login" type="submit">[[login:login]]</button> &nbsp; <a id="reset-link" class="hide" href="{relative_path}/reset">[[login:forgot_password]]</a>
<button class="btn btn-primary btn-lg btn-block" id="login" type="submit">[[login:login]]</button>
<!-- IF showResetLink -->
&nbsp; <a id="reset-link" href="{relative_path}/reset">[[login:forgot_password]]</a>
<!-- ENDIF showResetLink -->
</div>
</div>
<input type="hidden" name="_csrf" value="{token}" id="csrf-token" />

@ -21,7 +21,7 @@
<div class="category row">
<div class="col-md-12">
<ul id="topics-container">
<ul id="topics-container" data-nextstart="{nextStart}">
<!-- BEGIN topics -->
<li class="category-item {topics.deleted-class}">
<div class="col-md-12 col-xs-12 panel panel-default topic-row">

@ -13,8 +13,11 @@
</div>
</form>
<div class="category search">
<div class="{show_results}">
<div class="search favourites well">
<div class="{show_results} row">
<div id="topic-results" class="col-md-12" data-search-query="{search_query}">
<h3>[[topic:topics]]</h3>
<!-- IF topic_matches -->
@ -22,47 +25,74 @@
<!-- ENDIF topic_matches -->
<div class="alert alert-info {show_no_topics}">[[topic:no_topics_found]]</div>
<ul id="topics-container" data-search-query="{search_query}">
<!-- BEGIN topics -->
<li class="category-item">
<a href="{relative_path}/topic/{topics.slug}" id="tid-{topics.tid}">
<div class="topic-row panel panel-default clearfix">
<div class="panel-body">
<a href="../../user/{topics.userslug}">
<img title="{topics.username}" class="img-rounded user-img" src="{topics.picture}">
</a>
<a href="../../user/{topics.userslug}">
<strong><span>{topics.username}</span></strong>
</a>
<span class="search-result-text">
<p>{topics.title}</p>
</span>
<div>
<div class="col-md-12 img-thumbnail">
<div class="search-result-post">
<img src="{topics.teaser_userpicture}" />
<strong>{topics.teaser_username}</strong>: <span class="search-result-text">{topics.title}</span>
<small>
<span class="pull-right">
<a href="../../topic/{topics.slug}">posted</a>
in
<a href="../../category/{topics.categorySlug}">
<i class="fa {topics.categoryIcon}"></i> {topics.categoryName}
</a>
<span class="timeago" title="{topics.relativeTime}"></span>
</span>
</small>
</div>
</div>
</div>
</a>
</li>
<!-- END topics -->
</ul>
</div>
<div id="post-results" class="col-md-12" data-search-query="{search_query}">
<h3>Posts</h3>
<!-- IF post_matches -->
<small>{post_matches} result(s) matching "{search_query}"</small>
<!-- ENDIF post_matches -->
<div class="alert alert-info {show_no_posts}">No posts found!</div>
<ul id="topics-container" data-search-query="{search_query}">
<!-- BEGIN posts -->
<li class="category-item">
<a href="{relative_path}/topic/{posts.topicSlug}#{posts.pid}" id="tid-{posts.tid}">
<div class="topic-row panel panel-default clearfix">
<div class="panel-body">
<a href="../../user/{posts.userslug}">
<img title="{posts.username}" class="img-rounded user-img" src="{posts.picture}">
</a>
<a href="../../user/{posts.userslug}">
<strong><span>{posts.username}</span></strong>
</a>
<span class="search-result-text">
{posts.content}
</span>
<div>
<div class="col-md-12 img-thumbnail">
<div class="search-result-post">
<img src="{posts.picture}" />
<strong>{posts.username}</strong>: <span class="search-result-text">{posts.content}</span>
<small>
<span class="pull-right">
<a href="../../topic/{posts.topicSlug}#{posts.pid}">posted</a>
in
<a href="../../category/{posts.categorySlug}">
<i class="fa {posts.categoryIcon}"></i> {posts.categoryName}
</a>
<span class="timeago" title="{posts.relativeTime}"></span>
</span>
</small>
</div>
</div>
</div>
</a>
</li>
<!-- END posts -->
</ul>
</div>
</div>
</div>

@ -186,7 +186,7 @@
<!-- IF privileges.write -->
<button class="btn btn-primary post_reply" type="button">[[topic:reply]]</button>
<!-- ENDIF privileges.write -->
<div class="btn-group thread-tools hide">
<div class="btn-group thread-tools hide dropup">
<button class="btn btn-default dropdown-toggle" data-toggle="dropdown" type="button">[[topic:thread_tools.title]] <span class="caret"></span></button>
<ul class="dropdown-menu pull-right">
<li><a href="#" class="markAsUnreadForAll"><i class="fa fa-inbox"></i> [[topic:thread_tools.markAsUnreadForAll]]</a></li>

@ -16,7 +16,7 @@
<div class="category row">
<div class="col-md-12">
<ul id="topics-container" data-next-start="{nextStart}">
<ul id="topics-container" data-nextstart="{nextStart}">
<!-- BEGIN topics -->
<li class="category-item {topics.deleted-class}">
<div class="col-md-12 col-xs-12 panel panel-default topic-row">

@ -1,8 +1,8 @@
var db = require('./database.js'),
posts = require('./posts.js'),
utils = require('./../public/src/utils.js'),
user = require('./user.js'),
topics = require('./topics.js'),
var db = require('./database'),
posts = require('./posts'),
utils = require('./../public/src/utils'),
user = require('./user'),
topics = require('./topics'),
plugins = require('./plugins'),
CategoryTools = require('./categoryTools'),
meta = require('./meta'),
@ -52,8 +52,8 @@ var db = require('./database.js'),
return callback(err);
}
function getTopicIds(next) {
Categories.getTopicIds(category_id, start, end, next);
function getTopics(next) {
Categories.getCategoryTopics(category_id, start, end, current_user, next);
}
function getActiveUsers(next) {
@ -70,9 +70,12 @@ var db = require('./database.js'),
Categories.getPageCount(category_id, next);
}
async.parallel([getTopicIds, getActiveUsers, getSidebars, getPageCount], function(err, results) {
var tids = results[0],
active_users = results[1],
async.parallel([getTopics, getActiveUsers, getSidebars, getPageCount], function(err, results) {
if(err) {
return callback(err);
}
var active_users = results[1],
sidebars = results[2],
pageCount = results[3];
@ -87,27 +90,22 @@ var db = require('./database.js'),
'topic_row_size': 'col-md-9',
'category_id': category_id,
'active_users': [],
'topics': [],
'topics': results[0].topics,
'nextStart': results[0].nextStart,
'pageCount': pageCount,
'disableSocialButtons': meta.config.disableSocialButtons !== undefined ? parseInt(meta.config.disableSocialButtons, 10) !== 0 : false,
'sidebars': sidebars
};
function getTopics(next) {
topics.getTopicsByTids(tids, category_id, current_user, next);
}
function getModerators(next) {
Categories.getModerators(category_id, next);
}
function getActiveUsers(next) {
user.getMultipleUserFields(active_users, ['uid', 'username', 'userslug', 'picture'], function(err, users) {
next(err, users);
});
user.getMultipleUserFields(active_users, ['uid', 'username', 'userslug', 'picture'], next);
}
if (tids.length === 0) {
if (!category.topics.length) {
getModerators(function(err, moderators) {
category.moderator_block_class = moderators.length > 0 ? '' : 'none';
category.moderators = moderators;
@ -116,11 +114,10 @@ var db = require('./database.js'),
callback(null, category);
});
} else {
async.parallel([getTopics, getModerators, getActiveUsers], function(err, results) {
category.topics = results[0];
category.moderator_block_class = results[1].length > 0 ? '' : 'none';
category.moderators = results[1];
category.active_users = results[2];
async.parallel([getModerators, getActiveUsers], function(err, results) {
category.moderator_block_class = results[0].length > 0 ? '' : 'none';
category.moderators = results[0];
category.active_users = results[1];
category.show_sidebar = category.topics.length > 0 ? 'show' : 'hidden';
callback(null, category);
});
@ -131,13 +128,26 @@ var db = require('./database.js'),
};
Categories.getCategoryTopics = function(cid, start, stop, uid, callback) {
Categories.getTopicIds(cid, start, stop, function(err, tids) {
async.waterfall([
function(next) {
Categories.getTopicIds(cid, start, stop, next);
},
function(tids, next) {
topics.getTopicsByTids(tids, cid, uid, next);
},
function(topics, next) {
db.sortedSetRevRank('categories:' + cid + ':tid', topics[topics.length - 1].tid, function(err, rank) {
if(err) {
return callback(err);
return next(err);
}
topics.getTopicsByTids(tids, cid, uid, callback);
return next(null, {
topics: topics,
nextStart: parseInt(rank, 10) + 1
});
});
}
], callback);
};
Categories.getTopicIds = function(cid, start, stop, callback) {

@ -656,6 +656,23 @@
});
}
module.sortedSetRevRank = function(key, value, callback) {
if(value !== null && value !== undefined) {
value = value.toString();
}
module.getSortedSetRange(key, 0, -1, function(err, result) {
if(err) {
return callback(err);
}
var rank = result.indexOf(value);
if(rank === -1) {
return callback(null, null);
}
callback(null, result.length - rank - 1);
});
}
module.sortedSetScore = function(key, value, callback) {
if(value !== null && value !== undefined) {
value = value.toString();

@ -382,6 +382,10 @@
redisClient.zrank(key, value, callback);
}
module.sortedSetRevRank = function(key, value, callback) {
redisClient.zrevrank(key, value, callback);
}
module.sortedSetScore = function(key, value, callback) {
redisClient.zscore(key, value, callback);
}

@ -38,13 +38,17 @@
}
}
var description = topicData.posts.length ? topicData.posts[0].content : '';
var image_url = topicData.posts.length ? topicData.posts[0].picture : '';
var author = topicData.posts.length ? topicData.posts[0].username : '';
var feed = new rss({
title: topicData.topic_name,
description: topicData.posts[0].content,
description: description,
feed_url: Feed.defaults.baseUrl + '/topics/' + tid + '.rss',
site_url: nconf.get('url') + '/topic/' + topicData.slug,
image_url: topicData.posts[0].picture,
author: topicData.posts[0].username,
image_url: image_url,
author: author,
ttl: Feed.defaults.ttl
}),
dateStamp;

@ -1,5 +1,5 @@
var user = require('./user'),
bcrypt = require('bcrypt'),
bcrypt = require('bcryptjs'),
db = require('./database'),
path = require('path'),
winston = require('winston'),

@ -56,13 +56,16 @@ var db = require('./database'),
var messages = [];
userData[0].uid = touid;
userData[1].uid = fromuid;
function getMessage(mid, next) {
db.getObject('message:' + mid, function(err, message) {
if (err) {
return next(err);
}
Messaging.parse(message.content, message.fromuid, fromuid, userData[1], userData[0], function(result) {
Messaging.parse(message.content, message.fromuid, fromuid, userData[1], userData[0], false, function(result) {
message.content = result;
messages.push(message);
next(null);
@ -81,7 +84,7 @@ var db = require('./database'),
});
};
Messaging.parse = function (message, fromuid, myuid, toUserData, myUserData, callback) {
Messaging.parse = function (message, fromuid, myuid, toUserData, myUserData, isNew, callback) {
plugins.fireHook('filter:post.parse', message, function(err, parsed) {
if (err) {
return callback(message);
@ -97,7 +100,20 @@ var db = require('./database'),
username = '<span class="chat-user"> ' + toUserData.username + '</span>: ';
}
callback(picture + username + parsed);
var messageData = {
message: message,
parsed: parsed,
fromuid: fromuid,
myuid: myuid,
toUserData: toUserData,
myUserData: myUserData,
isNew: isNew,
parsedMessage: picture + username + parsed
};
plugins.fireHook('filter:messaging.parse', messageData, function(err, messageData) {
callback(messageData.parsedMessage);
});
});
};

@ -202,6 +202,10 @@ var fs = require('fs'),
} else return;
};
Plugins.hasListeners = function(hook) {
return (Plugins.loadedHooks[hook] && Plugins.loadedHooks[hook].length > 0);
};
Plugins.fireHook = function(hook, args, callback) {
hookList = Plugins.loadedHooks[hook];

@ -11,10 +11,11 @@ var path = require('path'),
posts = require('../posts'),
categories = require('../categories'),
categoryTools = require('../categoryTools')
meta = require('../meta'),
Plugins = require('../plugins'),
utils = require('../../public/src/utils'),
translator = require('../../public/src/translator'),
pkg = require('../../package.json'),
meta = require('../meta');
pkg = require('../../package.json');
(function (Api) {
@ -46,7 +47,6 @@ var path = require('path'),
config.topicsPerPage = meta.config.topicsPerPage || 20;
config.postsPerPage = meta.config.postsPerPage || 20;
config.maximumFileSize = meta.config.maximumFileSize;
config.emailSetup = !!meta.config['email:from'];
config.defaultLang = meta.config.defaultLang || 'en';
res.json(200, config);
@ -116,7 +116,8 @@ var path = require('path'),
app.get('/login', function (req, res) {
var data = {},
login_strategies = auth.get_login_strategies(),
num_strategies = login_strategies.length;
num_strategies = login_strategies.length,
emailersPresent = Plugins.hasListeners('action:email.send');
if (num_strategies == 0) {
data = {
@ -131,8 +132,8 @@ var path = require('path'),
}
data.authentication = login_strategies;
data.token = res.locals.csrf_token;
data.showResetLink = emailersPresent;
res.json(data);
});

@ -75,12 +75,12 @@ var DebugRoute = function(app) {
app.get('/test', function(req, res) {
/*topics.getTopicPosts2(2, 0, 10, 5, function(err, data) {
res.json(data);
})*/
topics.getTopicWithPosts(2, 1, 0, -1, true, function (err, topicData) {
res.json(topicData);
var db = require('./../database');
db.getSortedSetRevRange('topics:recent', 0 , -1, function(err, tids) {
res.json(tids);
});
});
});

@ -18,14 +18,10 @@ SocketCategories.loadMore = function(socket, data, callback) {
var topicsPerPage = parseInt(meta.config.topicsPerPage, 10) || 20;
var start = data.after,
var start = parseInt(data.after, 10),
end = start + topicsPerPage - 1;
categories.getCategoryTopics(data.cid, start, end, socket.uid, function(err, topics) {
callback(err, {
topics: topics
});
});
categories.getCategoryTopics(data.cid, start, end, socket.uid, callback);
};
SocketCategories.getPageCount = function(socket, cid, callback) {

@ -22,12 +22,11 @@ var SocketIO = require('socket.io'),
/* === */
var users = {},
io;
var io;
Sockets.userSockets = {};
Sockets.rooms = {};
Sockets.init = function(server) {
@ -59,9 +58,9 @@ Sockets.init = function(server) {
sessionID = socket.handshake.signedCookies["express.sid"];
db.sessionStore.get(sessionID, function(err, sessionData) {
if (!err && sessionData && sessionData.passport && sessionData.passport.user) {
uid = users[sessionID] = sessionData.passport.user;
uid = sessionData.passport.user;
} else {
uid = users[sessionID] = 0;
uid = 0;
}
socket.uid = parseInt(uid, 10);
@ -110,8 +109,8 @@ Sockets.init = function(server) {
}
if (Sockets.userSockets[uid] && Sockets.userSockets[uid].length === 0) {
delete users[sessionID];
delete Sockets.userSockets[uid];
if (uid) {
db.sortedSetRemove('users:online', uid, function(err, data) {
});
@ -126,17 +125,10 @@ Sockets.init = function(server) {
emitOnlineUserCount();
for (var roomName in Sockets.rooms) {
if (Sockets.rooms.hasOwnProperty(roomName)) {
socket.leave(roomName);
if (Sockets.rooms[roomName][socket.id]) {
delete Sockets.rooms[roomName][socket.id];
for(var roomName in io.sockets.manager.roomClients[socket.id]) {
updateRoomBrowsingText(roomName.slice(1));
}
updateRoomBrowsingText(roomName);
}
}
});
socket.on('*', function(payload, callback) {
@ -222,9 +214,10 @@ function updateRoomBrowsingText(roomName) {
function getUidsInRoom(room) {
var uids = [];
for (var socketId in room) {
if (uids.indexOf(room[socketId]) === -1) {
uids.push(room[socketId]);
var clients = io.sockets.clients(roomName);
for(var i=0; i<clients.length; ++i) {
if (uids.indexOf(clients[i].uid) === -1 && clients[i].uid !== 0) {
uids.push(clients[i].uid);
}
}
return uids;
@ -235,15 +228,14 @@ function updateRoomBrowsingText(roomName) {
var anonCount = 0;
for (var i = 0; i < clients.length; ++i) {
var hs = clients[i].handshake;
if (hs && clients[i].state && clients[i].state.user.uid === 0) {
if(clients[i].uid === 0) {
++anonCount;
}
}
return anonCount;
}
var uids = getUidsInRoom(Sockets.rooms[roomName]),
var uids = getUidsInRoom(roomName),
anonymousCount = getAnonymousCount(roomName);
user.getMultipleUserFields(uids, ['uid', 'username', 'userslug', 'picture'], function(err, users) {

@ -84,18 +84,6 @@ SocketMeta.rooms.enter = function(socket, data) {
}
socket.join(data.enter);
server.rooms[data.enter] = server.rooms[data.enter] || {};
if (socket.uid) {
server.rooms[data.enter][socket.id] = socket.uid;
if (data.leave && server.rooms[data.leave] && server.rooms[data.leave][socket.id] && data.enter !== data.leave) {
delete server.rooms[data.leave][socket.id];
if(!Object.keys(server.rooms[data.leave]).length) {
delete server.rooms[data.leave];
}
}
}
if (data.leave) {
module.parent.exports.updateRoomBrowsingText(data.leave);
@ -104,12 +92,12 @@ SocketMeta.rooms.enter = function(socket, data) {
module.parent.exports.updateRoomBrowsingText(data.enter);
if (data.enter != 'admin') {
server.in('admin').emit('event:meta.rooms.update', null, server.rooms);
server.in('admin').emit('event:meta.rooms.update', null, server.server.sockets.manager.rooms);
}
};
SocketMeta.rooms.getAll = function(socket, data, callback) {
callback(null, server.rooms);
callback(null, server.server.sockets.manager.rooms);
};
/* Exports */

@ -109,7 +109,11 @@ SocketModules.chats.send = function(socket, data) {
});
});
}
Messaging.parse(msg, socket.uid, socket.uid, usersData[1], usersData[0], function(parsed) {
usersData[0].uid = socket.uid;
usersData[1].uid = touid;
Messaging.parse(msg, socket.uid, socket.uid, usersData[1], usersData[0], true, function(parsed) {
Messaging.addMessage(socket.uid, touid, msg, function(err, message) {
var numSockets = 0,
x;

@ -93,7 +93,17 @@ SocketPosts.uploadFile = function(socket, data, callback) {
};
SocketPosts.getRawPost = function(socket, pid, callback) {
posts.getPostField(pid, 'content', callback);
posts.getPostFields(pid, ['content', 'deleted'], function(err, data) {
if(err) {
return callback(err);
}
if(data.deleted === '1') {
return callback(new Error('This post no longer exists'));
}
callback(null, data.content);
});
};
SocketPosts.edit = function(socket, data, callback) {

@ -1,6 +1,9 @@
var topics = require('../topics'),
threadTools = require('../threadTools'),
index = require('./index'),
async = require('async'),
SocketTopics = {};
SocketTopics.post = function(socket, data, callback) {
@ -233,15 +236,18 @@ SocketTopics.loadMore = function(socket, data, callback) {
var postsPerPage = parseInt(meta.config.postsPerPage, 10);
postsPerPage = postsPerPage ? postsPerPage : 20;
var start = data.after,
var start = parseInt(data.after, 10),
end = start + postsPerPage - 1;
topics.getTopicPosts(data.tid, start, end, socket.uid, function(err, posts) {
if(err) {
return callback(err);
async.parallel({
posts: function(next) {
topics.getTopicPosts(data.tid, start, end, socket.uid, next);
},
privileges: function(next) {
threadTools.privileges(data.tid, socket.uid, next);
}
callback(err, {posts: posts});
}, function(err, results) {
callback(err, results);
});
};
@ -250,14 +256,14 @@ SocketTopics.loadMoreRecentTopics = function(socket, data, callback) {
return callback(new Error('invalid data'));
}
var start = data.after,
var start = parseInt(data.after, 10),
end = start + 9;
topics.getLatestTopics(socket.uid, start, end, data.term, callback);
};
SocketTopics.loadMoreUnreadTopics = function(socket, data, callback) {
var start = data.after,
var start = parseInt(data.after, 10),
end = start + 9;
topics.getUnreadTopics(socket.uid, start, end, callback);

@ -187,9 +187,20 @@ var winston = require('winston'),
ThreadTools.move = function(tid, cid, callback) {
topics.getTopicFields(tid, ['cid', 'lastposttime'], function(err, topicData) {
if(err) {
return callback(err);
}
var oldCid = topicData.cid;
if(!oldCid) {
return callback(new Error('invalid-topic'));
}
db.sortedSetRemove('categories:' + oldCid + ':tid', tid, function(err, result) {
if(err) {
return callback(err);
}
db.sortedSetAdd('categories:' + cid + ':tid', topicData.lastposttime, tid, function(err, result) {
if(err) {

@ -426,8 +426,9 @@ var async = require('async'),
};
var since = terms['day'];
if(terms[term])
if(terms[term]) {
since = terms[term];
}
var args = ['topics:recent', '+inf', timestamp - since, 'LIMIT', start, end - start + 1];
db.getSortedSetRevRangeByScore(args, function(err, tids) {
@ -442,23 +443,29 @@ var async = require('async'),
if (!tids || !tids.length) {
latestTopics.no_topics_message = 'show';
callback(err, latestTopics);
return;
return callback(null, latestTopics);
}
// Filter out topics that belong to categories that this user cannot access
async.filter(tids, function(tid, next) {
threadTools.privileges(tid, current_user, function(err, privileges) {
if (!err && privileges.read) {
next(true);
} else {
next(false);
}
next(!err && privileges.read);
});
}, function(tids) {
Topics.getTopicsByTids(tids, 0, current_user, function(err, topicData) {
if(err) {
return callback(err);
}
if(!topicData || !topicData.length) {
latestTopics.no_topics_message = 'show';
return callback(null, latestTopics);
}
db.sortedSetRevRank('topics:recent', topicData[topicData.length - 1].tid, function(err, rank) {
latestTopics.nextStart = parseInt(rank,10) + 1;
latestTopics.topics = topicData;
callback(err, latestTopics);
callback(null, latestTopics);
});
});
});
});
@ -538,7 +545,7 @@ var async = require('async'),
return parseInt(read[index], 10) === 0;
});
// Filter out topics that belong to categories that this user cannot access
async.filter(newtids, function(tid, next) {
threadTools.privileges(tid, uid, function(err, privileges) {
if (!err && privileges.read) {
@ -588,8 +595,14 @@ var async = require('async'),
return callback(err);
}
db.sortedSetRevRank('topics:recent', topicData[topicData.length - 1].tid, function(err, rank) {
if(err) {
return callback(err);
}
unreadTopics.topics = topicData;
unreadTopics.nextStart = stop + 1;
unreadTopics.nextStart = parseInt(rank, 10) + 1;
if (!topicData || topicData.length === 0) {
unreadTopics.no_topics_message = 'show';
}
@ -599,6 +612,7 @@ var async = require('async'),
callback(null, unreadTopics);
});
});
}
Topics.getUnreadTids(uid, start, stop, function(err, unreadTids) {
@ -700,6 +714,7 @@ var async = require('async'),
function isTopicVisible(topicData, topicInfo) {
var deleted = parseInt(topicData.deleted, 10) !== 0;
return !deleted || (deleted && topicInfo.privileges.view_deleted) || topicData.uid === current_user;
}

@ -1,4 +1,4 @@
var bcrypt = require('bcrypt'),
var bcrypt = require('bcryptjs'),
async = require('async'),
nconf = require('nconf'),
winston = require('winston'),
@ -859,6 +859,10 @@ var bcrypt = require('bcrypt'),
User.email = {
verify: function(uid, email) {
if (!plugins.hasListeners('action:email.send')) {
return;
}
var confirm_code = utils.generateUUID(),
confirm_link = nconf.get('url') + '/confirm/' + confirm_code;
@ -895,11 +899,12 @@ var bcrypt = require('bcrypt'),
confirm: function(code, callback) {
db.getObject('confirm:' + code, function(err, confirmObj) {
if (err) {
callback({
return callback({
status:'error'
});
} else {
if (confirmObj.uid && confirmObj.email) {
}
if (confirmObj && confirmObj.uid && confirmObj.email) {
db.setObjectField('email:confirmed', confirmObj.email, '1', function() {
callback({
status: 'ok'
@ -910,7 +915,6 @@ var bcrypt = require('bcrypt'),
status: 'not_ok'
});
}
}
});
}
};

@ -43,9 +43,9 @@ describe('Categories', function() {
describe('.getCategoryTopics', function() {
it('should return a list of topics', function(done) {
Categories.getCategoryTopics(categoryObj.cid, 0, 10, 0, function(err, topics) {
assert(Array.isArray(topics));
assert(topics.every(function(topic) {
Categories.getCategoryTopics(categoryObj.cid, 0, 10, 0, function(err, result) {
assert(Array.isArray(result.topics));
assert(result.topics.every(function(topic) {
return topic instanceof Object;
}));

Loading…
Cancel
Save