Merge remote-tracking branch 'origin/master' into private-groups

v1.18.x
Julian Lam 10 years ago
commit a5d7fee623

@ -1,5 +1,7 @@
{ {
"results_matching": "%1 result(s) matching \"%2\", (%3 seconds)", "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)",
"no-matches": "No matches found", "no-matches": "No matches found",
"in": "In" "in": "In",
"by": "By",
"posted-by": "Posted by"
} }

@ -112,5 +112,6 @@
"sort_by": "Sort by", "sort_by": "Sort by",
"oldest_to_newest": "Oldest to Newest", "oldest_to_newest": "Oldest to Newest",
"newest_to_oldest": "Newest to Oldest", "newest_to_oldest": "Newest to Oldest",
"most_votes": "Most votes" "most_votes": "Most votes",
"most_posts": "Most posts"
} }

@ -28,15 +28,19 @@ $(document).ready(function() {
textStatus = err.textStatus; textStatus = err.textStatus;
if (data) { if (data) {
if (data.status === 403 || data.status === 404 || data.status === 500) { var status = parseInt(data.status, 10);
if (status === 403 || status === 404 || status === 500) {
$('#footer, #content').removeClass('hide').addClass('ajaxifying'); $('#footer, #content').removeClass('hide').addClass('ajaxifying');
return renderTemplate(url, data.status.toString(), data.responseJSON, (new Date()).getTime(), callback); return renderTemplate(url, status.toString(), data.responseJSON, (new Date()).getTime(), callback);
} else if (data.status === 401) { } else if (status === 401) {
app.alertError('[[global:please_log_in]]'); app.alertError('[[global:please_log_in]]');
app.previousUrl = url; app.previousUrl = url;
return ajaxify.go('login'); return ajaxify.go('login');
} else if (data.status === 302) { } else if (status === 302) {
return ajaxify.go(data.responseJSON.slice(1), callback, quiet); if (!ajaxify.go(data.responseJSON.path, callback, quiet)) {
window.location.href = data.responseJSON.path;
}
} }
} else if (textStatus !== "abort") { } else if (textStatus !== "abort") {
app.alertError(data.responseJSON.error); app.alertError(data.responseJSON.error);

@ -437,7 +437,7 @@ app.uid = null;
e.preventDefault(); e.preventDefault();
var input = $(this).find('input'); var input = $(this).find('input');
search.query(input.val(), 'posts', function() { search.query({term: input.val(), in: 'posts'}, function() {
input.val(''); input.val('');
}); });
}); });

@ -1,7 +1,15 @@
"use strict"; "use strict";
/* global define, config, templates, app, utils, ajaxify, socket, translator */ /* global define, config, templates, app, utils, ajaxify, socket, translator */
define('forum/category', ['composer', 'forum/pagination', 'forum/infinitescroll', 'share', 'navigator', 'forum/categoryTools'], function(composer, pagination, infinitescroll, share, navigator, categoryTools) { define('forum/category', [
'composer',
'forum/pagination',
'forum/infinitescroll',
'share',
'navigator',
'forum/categoryTools',
'sort'
], function(composer, pagination, infinitescroll, share, navigator, categoryTools, sort) {
var Category = {}; var Category = {};
$(window).on('action:ajaxify.start', function(ev, data) { $(window).on('action:ajaxify.start', function(ev, data) {
@ -33,6 +41,8 @@ define('forum/category', ['composer', 'forum/pagination', 'forum/infinitescroll'
categoryTools.init(cid); categoryTools.init(cid);
sort.handleSort('categoryTopicSort', 'user.setCategorySort', 'category/' + ajaxify.variables.get('category_slug'));
enableInfiniteLoadingOrPagination(); enableInfiniteLoadingOrPagination();
if (!config.usePagination) { if (!config.usePagination) {

@ -1,18 +1,51 @@
'use strict';
/* globals app, define, utils, socket*/
define('forum/search', ['search'], function(searchModule) { define('forum/search', ['search'], function(searchModule) {
var Search = {}; var Search = {};
Search.init = function() { Search.init = function() {
var searchQuery = $('#results').attr('data-search-query'); var searchQuery = $('#results').attr('data-search-query');
var regexes = [];
var searchTerms = searchQuery.split(' ');
$('#advanced-search input').val(searchQuery); $('#advanced-search #search-input').val(searchQuery);
var params = utils.params(); var params = utils.params();
var select = $('#advanced-search select');
if (params && params.in) { if (params && params.in) {
$('#advanced-search select').val(params.in); select.val(params.in);
} }
if (params && params.by) {
$('.by-container #posted-by-input').val(params.by);
}
select.on('change', function() {
$('.by-container').toggleClass('hide', select.val() !== 'posts');
});
highlightMatches(searchQuery);
$('#advanced-search').off('submit').on('submit', function(e) {
e.preventDefault();
var input = $(this).find('#search-input');
var searchIn = $(this).find('select');
var postedBy = $(this).find('#posted-by-input');
searchModule.query({
term: input.val(),
in: searchIn.val(),
by: postedBy.val()
}, function() {
input.val('');
});
});
enableAutoComplete();
};
function highlightMatches(searchQuery) {
var searchTerms = searchQuery.split(' ');
var regexes = [];
for (var i=0; i<searchTerms.length; ++i) { for (var i=0; i<searchTerms.length; ++i) {
var regex = new RegExp(searchTerms[i], 'gi'); var regex = new RegExp(searchTerms[i], 'gi');
regexes.push({regex: regex, term: searchTerms[i]}); regexes.push({regex: regex, term: searchTerms[i]});
@ -26,18 +59,30 @@ define('forum/search', ['search'], function(searchModule) {
} }
result.html(text).find('img').addClass('img-responsive'); result.html(text).find('img').addClass('img-responsive');
}); });
}
$('#advanced-search').off('submit').on('submit', function(e) { function enableAutoComplete() {
e.preventDefault(); var input = $('.by-container #posted-by-input');
var input = $(this).find('input'); input.autocomplete({
var searchIn = $(this).find('select'); delay: 100,
source: function(request, response) {
socket.emit('user.search', {query: request.term}, function(err, result) {
if (err) {
return app.alertError(err.message);
}
searchModule.query(input.val(), searchIn.val(), function() { if (result && result.users) {
input.val(''); var names = result.users.map(function(user) {
}); return user && user.username;
});
response(names);
}
$('.ui-autocomplete a').attr('data-ajaxify', 'false');
});
}
}); });
}; }
return Search; return Search;
}); });

@ -11,8 +11,9 @@ define('forum/topic', [
'forum/topic/events', 'forum/topic/events',
'forum/topic/browsing', 'forum/topic/browsing',
'forum/topic/posts', 'forum/topic/posts',
'navigator' 'navigator',
], function(pagination, infinitescroll, threadTools, postTools, events, browsing, posts, navigator) { 'sort'
], function(pagination, infinitescroll, threadTools, postTools, events, browsing, posts, navigator, sort) {
var Topic = {}, var Topic = {},
currentUrl = ''; currentUrl = '';
@ -44,7 +45,7 @@ define('forum/topic', [
threadTools.init(tid, thread_state); threadTools.init(tid, thread_state);
events.init(); events.init();
handleSorting(); sort.handleSort('topicPostSort', 'user.setTopicSort', 'topic/' + ajaxify.variables.get('topic_slug'));
enableInfiniteLoadingOrPagination(); enableInfiniteLoadingOrPagination();
@ -107,21 +108,6 @@ define('forum/topic', [
return parts[parts.length - 1] ? parseInt(parts[parts.length - 1], 10) : 0; return parts[parts.length - 1] ? parseInt(parts[parts.length - 1], 10) : 0;
} }
function handleSorting() {
var threadSort = $('.thread-sort');
threadSort.find('i').removeClass('fa-check');
var currentSetting = threadSort.find('a[data-sort="' + config.topicPostSort + '"]');
currentSetting.find('i').addClass('fa-check');
$('.thread-sort').on('click', 'a', function() {
var newSetting = $(this).attr('data-sort');
socket.emit('user.setTopicSort', newSetting, function(err) {
config.topicPostSort = newSetting;
ajaxify.go('topic/' + ajaxify.variables.get('topic_slug'));
});
});
}
function addBlockQuoteHandler() { function addBlockQuoteHandler() {
$('#post-container').on('click', 'blockquote .toggle', function() { $('#post-container').on('click', 'blockquote .toggle', function() {
var blockQuote = $(this).parent('blockquote'); var blockQuote = $(this).parent('blockquote');

@ -115,15 +115,14 @@ define('forum/users', function() {
notify.html('<i class="fa fa-spinner fa-spin"></i>'); notify.html('<i class="fa fa-spinner fa-spin"></i>');
socket.emit('user.search', username, function(err, data) { socket.emit('user.search', {query: username}, function(err, data) {
if (err) { if (err) {
reset(); reset();
return app.alertError(err.message); return app.alertError(err.message);
} }
if (!data) { if (!data) {
reset(); return reset();
return;
} }
templates.parse('users', 'users', data, function(html) { templates.parse('users', 'users', data, function(html) {

@ -7,7 +7,11 @@ define('search', ['navigator'], function(nav) {
current: {} current: {}
}; };
Search.query = function(term, searchIn, callback) { Search.query = function(data, callback) {
var term = data.term;
var searchIn = data.in || 'posts';
var postedBy = data.by || '';
// Detect if a tid was specified // Detect if a tid was specified
var topicSearch = term.match(/in:topic-([\d]+)/); var topicSearch = term.match(/in:topic-([\d]+)/);
@ -19,8 +23,11 @@ define('search', ['navigator'], function(nav) {
} catch(e) { } catch(e) {
return app.alertError('[[error:invalid-search-term]]'); return app.alertError('[[error:invalid-search-term]]');
} }
var query = {in: searchIn};
ajaxify.go('search/' + term + (searchIn ? '?in=' + searchIn : '')); if (postedBy && searchIn === 'posts') {
query.by = postedBy;
}
ajaxify.go('search/' + term + '?' + decodeURIComponent($.param(query)));
callback(); callback();
} else { } else {
var cleanedTerm = term.replace(topicSearch[0], ''), var cleanedTerm = term.replace(topicSearch[0], ''),

@ -0,0 +1,26 @@
'use strict';
/* globals define, translator, templates */
define('sort', function() {
var module = {};
module.handleSort = function (field, method, gotoOnSave) {
var threadSort = $('.thread-sort');
threadSort.find('i').removeClass('fa-check');
var currentSetting = threadSort.find('a[data-sort="' + config[field] + '"]');
currentSetting.find('i').addClass('fa-check');
$('.thread-sort').on('click', 'a', function() {
var newSetting = $(this).attr('data-sort');
socket.emit(method, newSetting, function(err) {
if (err) {
return app.alertError(err.message);
}
config[field] = newSetting;
ajaxify.go(gotoOnSave);
});
});
};
return module;
});

@ -21,6 +21,16 @@
languages[language].loading = languages[language].loading || {}; languages[language].loading = languages[language].loading || {};
}; };
translator.getTranslations = function(language, filename, callback) {
if (languages[language] && languages[language].loaded[filename]) {
callback(languages[language].loaded[filename]);
} else {
translator.load(language, filename, function() {
callback(languages[language].loaded[filename]);
});
}
}
translator.getLanguage = function() { translator.getLanguage = function() {
return config.defaultLang; return config.defaultLang;
}; };
@ -180,7 +190,7 @@
callback(translations); callback(translations);
} }
while (languages[language].callbacks[filename] && languages[language].callbacks[filename].length) { while (languages[language].callbacks && languages[language].callbacks[filename] && languages[language].callbacks[filename].length) {
languages[language].callbacks[filename].pop()(translations); languages[language].callbacks[filename].pop()(translations);
} }

@ -40,10 +40,11 @@ var async = require('async'),
topics: function(next) { topics: function(next) {
Categories.getCategoryTopics({ Categories.getCategoryTopics({
cid: data.cid, cid: data.cid,
set: data.set,
reverse: data.reverse,
start: data.start, start: data.start,
stop: data.end, stop: data.end,
uid: data.uid, uid: data.uid
targetUid: data.targetUid
}, next); }, next);
}, },
pageCount: function(next) { pageCount: function(next) {

@ -29,6 +29,7 @@ module.exports = function(Categories) {
function(next) { function(next) {
db.deleteAll([ db.deleteAll([
'cid:' + cid + ':tids', 'cid:' + cid + ':tids',
'cid:' + cid + ':tids:posts',
'cid:' + cid + ':pids', 'cid:' + cid + ':pids',
'category:' + cid 'category:' + cid
], next); ], next);

@ -22,7 +22,7 @@ module.exports = function(Categories) {
plugins.fireHook('filter:category.topics.prepare', data, next); plugins.fireHook('filter:category.topics.prepare', data, next);
}, },
function(data, next) { function(data, next) {
Categories.getTopicIds(data.targetUid ? 'cid:' + data.cid + ':uid:' + data.targetUid + ':tids' : 'cid:' + data.cid + ':tids', data.start, data.stop, next); Categories.getTopicIds(data.set, data.reverse, data.start, data.stop, next);
}, },
function(tids, next) { function(tids, next) {
topics.getTopicsByTids(tids, data.uid, next); topics.getTopicsByTids(tids, data.uid, next);
@ -56,8 +56,12 @@ module.exports = function(Categories) {
}); });
}; };
Categories.getTopicIds = function(set, start, stop, callback) { Categories.getTopicIds = function(set, reverse, start, stop, callback) {
db.getSortedSetRevRange(set, start, stop, callback); if (reverse) {
db.getSortedSetRevRange(set, start, stop, callback);
} else {
db.getSortedSetRange(set, start, stop, callback);
}
}; };
Categories.getTopicIndex = function(tid, callback) { Categories.getTopicIndex = function(tid, callback) {
@ -95,6 +99,9 @@ module.exports = function(Categories) {
} else { } else {
db.sortedSetAdd('cid:' + cid + ':tids', postData.timestamp, postData.tid, next); db.sortedSetAdd('cid:' + cid + ':tids', postData.timestamp, postData.tid, next);
} }
},
function(next) {
db.sortedSetIncrBy('cid:' + cid + ':tids:posts', 1, postData.tid, next);
} }
], callback); ], callback);
}); });

@ -55,6 +55,7 @@ apiController.getConfig = function(req, res, next) {
config['css-buster'] = meta.css.hash; config['css-buster'] = meta.css.hash;
config.requireEmailConfirmation = parseInt(meta.config.requireEmailConfirmation, 10) === 1; config.requireEmailConfirmation = parseInt(meta.config.requireEmailConfirmation, 10) === 1;
config.topicPostSort = meta.config.topicPostSort || 'oldest_to_newest'; config.topicPostSort = meta.config.topicPostSort || 'oldest_to_newest';
config.categoryTopicSort = meta.config.categoryTopicSort || 'newest_to_oldest';
config.csrf_token = req.csrfToken(); config.csrf_token = req.csrfToken();
config.searchEnabled = plugins.hasListeners('filter:search.query'); config.searchEnabled = plugins.hasListeners('filter:search.query');
@ -79,6 +80,7 @@ apiController.getConfig = function(req, res, next) {
config.userLang = settings.language || config.defaultLang; config.userLang = settings.language || config.defaultLang;
config.openOutgoingLinksInNewTab = settings.openOutgoingLinksInNewTab; config.openOutgoingLinksInNewTab = settings.openOutgoingLinksInNewTab;
config.topicPostSort = settings.topicPostSort || config.topicPostSort; config.topicPostSort = settings.topicPostSort || config.topicPostSort;
config.categoryTopicSort = settings.categoryTopicSort || config.categoryTopicSort;
config.topicSearchEnabled = settings.topicSearchEnabled || false; config.topicSearchEnabled = settings.topicSearchEnabled || false;
if (res.locals.isAPI) { if (res.locals.isAPI) {

@ -158,11 +158,23 @@ categoriesController.get = function(req, res, next) {
topicIndex = 0; topicIndex = 0;
} }
var set = 'cid:' + cid + ':tids',
reverse = false;
if (settings.categoryTopicSort === 'newest_to_oldest') {
reverse = true;
} else if (settings.categoryTopicSort === 'most_posts') {
reverse = true;
set = 'cid:' + cid + ':tids:posts';
}
var start = (page - 1) * settings.topicsPerPage + topicIndex, var start = (page - 1) * settings.topicsPerPage + topicIndex,
end = start + settings.topicsPerPage - 1; end = start + settings.topicsPerPage - 1;
next(null, { next(null, {
cid: cid, cid: cid,
set: set,
reverse: reverse,
start: start, start: start,
end: end, end: end,
uid: uid uid: uid
@ -171,6 +183,9 @@ categoriesController.get = function(req, res, next) {
function(payload, next) { function(payload, next) {
user.getUidByUserslug(req.query.author, function(err, uid) { user.getUidByUserslug(req.query.author, function(err, uid) {
payload.targetUid = uid; payload.targetUid = uid;
if (uid) {
payload.set = 'cid:' + cid + ':uid:' + uid + ':tids';
}
next(err, payload); next(err, payload);
}); });
}, },

@ -28,7 +28,12 @@ searchController.search = function(req, res, next) {
req.params.term = validator.escape(req.params.term); req.params.term = validator.escape(req.params.term);
search.search(req.params.term, req.query.in, uid, function(err, results) { search.search({
query: req.params.term,
searchIn: req.query.in,
postedBy: req.query.by,
uid: uid
}, function(err, results) {
if (err) { if (err) {
return next(err); return next(err);
} }

@ -156,7 +156,7 @@ var fs = require('fs'),
winston.warn('[plugins/' + plugin.id + '] A templates directory was defined for this plugin, but was not found.'); winston.warn('[plugins/' + plugin.id + '] A templates directory was defined for this plugin, but was not found.');
} }
next(err); next(false);
}); });
} else { } else {
next(false); next(false);

@ -171,8 +171,11 @@ module.exports = function(Posts) {
topics.updateTeaser(postData.tid, next); topics.updateTeaser(postData.tid, next);
}, },
function(next) { function(next) {
user.incrementUserPostCountBy(postData.uid, -1, next); db.sortedSetIncrBy('cid:' + topicData.cid + ':tids:posts', -1, postData.tid, next);
}, },
function(next) {
user.incrementUserPostCountBy(postData.uid, -1, next);
}
], callback); ], callback);
}); });
}); });

@ -125,6 +125,8 @@ function generateForCategory(req, res, next) {
var uid = req.user ? req.user.uid : 0; var uid = req.user ? req.user.uid : 0;
categories.getCategoryById({ categories.getCategoryById({
cid: cid, cid: cid,
set: 'cid:' + cid + ':tids',
reverse: true,
start: 0, start: 0,
end: 25, end: 25,
uid: uid uid: uid

@ -11,7 +11,7 @@ var search = {};
module.exports = search; module.exports = search;
search.search = function(query, searchIn, uid, callback) { search.search = function(data, callback) {
function done(err, data) { function done(err, data) {
if (err) { if (err) {
return callback(err); return callback(err);
@ -20,12 +20,16 @@ search.search = function(query, searchIn, uid, callback) {
result.search_query = query; result.search_query = query;
result[searchIn] = data; result[searchIn] = data;
result.matchCount = data.length; result.matchCount = data.length;
result.hidePostedBy = searchIn !== 'posts';
result.time = (process.elapsedTimeSince(start) / 1000).toFixed(2); result.time = (process.elapsedTimeSince(start) / 1000).toFixed(2);
callback(null, result); callback(null, result);
} }
var start = process.hrtime(); var start = process.hrtime();
searchIn = searchIn || 'posts';
var query = data.query;
var searchIn = data.searchIn || 'posts';
var uid = data.uid || 0;
var result = { var result = {
posts: [], posts: [],
@ -34,7 +38,7 @@ search.search = function(query, searchIn, uid, callback) {
}; };
if (searchIn === 'posts') { if (searchIn === 'posts') {
searchInPosts(query, uid, done); searchInPosts(query, data.postedBy, uid, done);
} else if (searchIn === 'users') { } else if (searchIn === 'users') {
searchInUsers(query, done); searchInUsers(query, done);
} else if (searchIn === 'tags') { } else if (searchIn === 'tags') {
@ -44,13 +48,20 @@ search.search = function(query, searchIn, uid, callback) {
} }
}; };
function searchInPosts(query, uid, callback) { function searchInPosts(query, postedBy, uid, callback) {
async.parallel({ async.parallel({
pids: function(next) { pids: function(next) {
searchQuery('post', query, next); searchQuery('post', query, next);
}, },
tids: function(next) { tids: function(next) {
searchQuery('topic', query, next); searchQuery('topic', query, next);
},
postedByUid: function(next) {
if (postedBy) {
user.getUidByUsername(postedBy, next);
} else {
next(null, 0);
}
} }
}, function (err, results) { }, function (err, results) {
if (err) { if (err) {
@ -75,6 +86,14 @@ function searchInPosts(query, uid, callback) {
}, },
function(pids, next) { function(pids, next) {
posts.getPostSummaryByPids(pids, uid, {stripTags: true, parse: false}, next); posts.getPostSummaryByPids(pids, uid, {stripTags: true, parse: false}, next);
},
function(posts, next) {
if (postedBy) {
posts = posts.filter(function(post) {
return post && parseInt(post.uid, 10) === parseInt(results.postedByUid, 10);
});
}
next(null, posts);
} }
], callback); ], callback);
}); });

@ -19,7 +19,7 @@ SocketCategories.get = function(socket, data, callback) {
}; };
SocketCategories.loadMore = function(socket, data, callback) { SocketCategories.loadMore = function(socket, data, callback) {
if(!data) { if (!data) {
return callback(new Error('[[error:invalid-data]]')); return callback(new Error('[[error:invalid-data]]'));
} }
@ -46,11 +46,28 @@ SocketCategories.loadMore = function(socket, data, callback) {
return callback(new Error('[[error:no-privileges]]')); return callback(new Error('[[error:no-privileges]]'));
} }
var set = 'cid:' + data.cid + ':tids',
reverse = false;
if (results.settings.categoryTopicSort === 'newest_to_oldest') {
reverse = true;
} else if (results.settings.categoryTopicSort === 'most_posts') {
reverse = true;
set = 'cid:' + data.cid + ':tids:posts';
}
var start = parseInt(data.after, 10), var start = parseInt(data.after, 10),
end = start + results.settings.topicsPerPage - 1; end = start + results.settings.topicsPerPage - 1;
if (results.targetUid) {
set = 'cid:' + data.cid + ':uid:' + results.targetUid + ':tids';
}
categories.getCategoryTopics({ categories.getCategoryTopics({
cid: data.cid, cid: data.cid,
set: set,
reverse: reverse,
start: start, start: start,
stop: end, stop: end,
uid: socket.uid, uid: socket.uid,

@ -392,7 +392,7 @@ SocketTopics.moveAll = function(socket, data, callback) {
return callback(err || new Error('[[error:no-privileges]]')); return callback(err || new Error('[[error:no-privileges]]'));
} }
categories.getTopicIds('cid:' + data.currentCid + ':tids', 0, -1, function(err, tids) { categories.getTopicIds('cid:' + data.currentCid + ':tids', true, 0, -1, function(err, tids) {
if (err) { if (err) {
return callback(err); return callback(err);
} }

@ -62,11 +62,14 @@ SocketUser.increaseViewCount = function(socket, uid, callback) {
} }
}; };
SocketUser.search = function(socket, username, callback) { SocketUser.search = function(socket, data, callback) {
if (!data) {
return callback(new Error('[[error:invalid-data]]'))
}
if (!socket.uid) { if (!socket.uid) {
return callback(new Error('[[error:not-logged-in]]')); return callback(new Error('[[error:not-logged-in]]'));
} }
user.search({query: username}, callback); user.search({query: data.query}, callback);
}; };
// Password Reset // Password Reset
@ -295,6 +298,12 @@ SocketUser.setTopicSort = function(socket, sort, callback) {
} }
}; };
SocketUser.setCategorySort = function(socket, sort, callback) {
if (socket.uid) {
user.setSetting(socket.uid, 'categoryTopicSort', sort, callback);
}
};
SocketUser.getOnlineAnonCount = function(socket, data, callback) { SocketUser.getOnlineAnonCount = function(socket, data, callback) {
callback(null, module.parent.exports.getOnlineAnonCount()); callback(null, module.parent.exports.getOnlineAnonCount());
}; };

@ -185,15 +185,26 @@ var winston = require('winston'),
var topic; var topic;
async.waterfall([ async.waterfall([
function(next) { function(next) {
topics.getTopicFields(tid, ['cid', 'lastposttime', 'pinned', 'deleted'], next); topics.getTopicFields(tid, ['cid', 'lastposttime', 'pinned', 'deleted', 'postcount'], next);
}, },
function(topicData, next) { function(topicData, next) {
topic = topicData; topic = topicData;
db.sortedSetRemove('cid:' + topicData.cid + ':tids', tid, next); db.sortedSetsRemove([
'cid:' + topicData.cid + ':tids',
'cid:' + topicData.cid + ':tids:posts'
], tid, next);
}, },
function(next) { function(next) {
var timestamp = parseInt(topic.pinned, 10) ? Math.pow(2, 53) : topic.lastposttime; var timestamp = parseInt(topic.pinned, 10) ? Math.pow(2, 53) : topic.lastposttime;
db.sortedSetAdd('cid:' + cid + ':tids', timestamp, tid, next); async.parallel([
function(next) {
db.sortedSetAdd('cid:' + cid + ':tids', timestamp, tid, next);
},
function(next) {
topic.postcount = topic.postcount || 0;
db.sortedSetAdd('cid:' + cid + ':tids:posts', topic.postcount, tid, next);
}
], next);
} }
], function(err) { ], function(err) {
if (err) { if (err) {

@ -76,6 +76,7 @@ module.exports = function(Topics) {
db.sortedSetsRemove([ db.sortedSetsRemove([
'cid:' + topicData.cid + ':tids', 'cid:' + topicData.cid + ':tids',
'cid:' + topicData.cid + ':tids:posts',
'cid:' + topicData.cid + ':uid:' + topicData.uid + ':tids', 'cid:' + topicData.cid + ':uid:' + topicData.uid + ':tids',
'uid:' + topicData.uid + ':topics' 'uid:' + topicData.uid + ':topics'
], tid, callback); ], tid, callback);

@ -21,7 +21,7 @@ var db = require('./database'),
schemaDate, thisSchemaDate, schemaDate, thisSchemaDate,
// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema // IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema
latestSchema = Date.UTC(2014, 11, 20); latestSchema = Date.UTC(2015, 0, 8);
Upgrade.check = function(callback) { Upgrade.check = function(callback) {
db.get('schemaDate', function(err, value) { db.get('schemaDate', function(err, value) {
@ -451,8 +451,48 @@ Upgrade.upgrade = function(callback) {
winston.info('[2014/12/20] Updating digest settings skipped'); winston.info('[2014/12/20] Updating digest settings skipped');
next(); next();
} }
},
function(next) {
thisSchemaDate = Date.UTC(2015, 0, 8);
if (schemaDate < thisSchemaDate) {
winston.info('[2015/01/08] Updating category topics sorted sets');
db.getSortedSetRange('topics:tid', 0, -1, function(err, tids) {
if (err) {
winston.error('[2014/12/20] Error encountered while updating digest settings');
return next(err);
}
var now = Date.now();
async.eachLimit(tids, 50, function(tid, next) {
db.getObjectFields('topic:' + tid, ['cid', 'postcount'], function(err, topicData) {
if (err) {
return next(err);
}
if (Utils.isNumber(topicData.postcount) && topicData.cid) {
db.sortedSetAdd('cid:' + topicData.cid + ':tids:posts', topicData.postcount, tid, next);
} else {
next();
}
});
}, function(err) {
if (err) {
winston.error('[2015/01/08] Error encountered while Updating category topics sorted sets');
return next(err);
}
winston.info('[2015/01/08] Updating category topics sorted sets done');
Upgrade.update(thisSchemaDate, next);
});
});
} else {
winston.info('[2015/01/08] Updating category topics sorted sets skipped');
next();
}
} }
// Add new schema updates here // Add new schema updates here
// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema IN LINE 22!!! // IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema IN LINE 22!!!
], function(err) { ], function(err) {

@ -65,6 +65,7 @@ module.exports = function(User) {
settings.notificationSounds = parseInt(settings.notificationSounds, 10) === 1; settings.notificationSounds = parseInt(settings.notificationSounds, 10) === 1;
settings.language = settings.language || meta.config.defaultLang || 'en_GB'; settings.language = settings.language || meta.config.defaultLang || 'en_GB';
settings.topicPostSort = settings.topicPostSort || meta.config.topicPostSort || 'oldest_to_newest'; settings.topicPostSort = settings.topicPostSort || meta.config.topicPostSort || 'oldest_to_newest';
settings.categoryTopicSort = settings.categoryTopicSort || meta.config.categoryTopicSort || 'newest_to_oldest';
settings.followTopicsOnCreate = (settings.followTopicsOnCreate === null || settings.followTopicsOnCreate === undefined) ? true : parseInt(settings.followTopicsOnCreate, 10) === 1; settings.followTopicsOnCreate = (settings.followTopicsOnCreate === null || settings.followTopicsOnCreate === undefined) ? true : parseInt(settings.followTopicsOnCreate, 10) === 1;
settings.followTopicsOnReply = parseInt(settings.followTopicsOnReply, 10) === 1; settings.followTopicsOnReply = parseInt(settings.followTopicsOnReply, 10) === 1;
settings.sendChatNotifications = parseInt(settings.sendChatNotifications, 10) === 1; settings.sendChatNotifications = parseInt(settings.sendChatNotifications, 10) === 1;

@ -12,6 +12,14 @@
<option value="most_votes">Most Votes</option> <option value="most_votes">Most Votes</option>
</select> </select>
</div> </div>
<div class="form-group">
<label>Default Topic Sorting</label>
<select class="form-control" data-field="categoryTopicSort">
<option value="newest_to_oldest">Newest to Oldest</option>
<option value="oldest_to_newest">Oldest to Newest</option>
<option value="most_posts">Most Posts</option>
</select>
</div>
<div class="form-group"> <div class="form-group">
<label>Seconds between Posts</label> <label>Seconds between Posts</label>

@ -35,6 +35,8 @@ describe('Categories', function() {
it('should retrieve a newly created category by its ID', function(done) { it('should retrieve a newly created category by its ID', function(done) {
Categories.getCategoryById({ Categories.getCategoryById({
cid: categoryObj.cid, cid: categoryObj.cid,
set: 'cid:' + categoryObj.cid + ':tids',
reverse: true,
start: 0, start: 0,
end: -1, end: -1,
uid: 0 uid: 0
@ -52,6 +54,8 @@ describe('Categories', function() {
it('should return a list of topics', function(done) { it('should return a list of topics', function(done) {
Categories.getCategoryTopics({ Categories.getCategoryTopics({
cid: categoryObj.cid, cid: categoryObj.cid,
set: 'cid:' + categoryObj.cid + ':tids',
reverse: true,
start: 0, start: 0,
stop: 10, stop: 10,
uid: 0 uid: 0
@ -68,6 +72,8 @@ describe('Categories', function() {
it('should return a list of topics by a specific user', function(done) { it('should return a list of topics by a specific user', function(done) {
Categories.getCategoryTopics({ Categories.getCategoryTopics({
cid: categoryObj.cid, cid: categoryObj.cid,
set: 'cid:' + categoryObj.cid + ':uid:' + 1 + ':tids',
reverse: true,
start: 0, start: 0,
stop: 10, stop: 10,
uid: 0, uid: 0,

Loading…
Cancel
Save