mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-10 16:05:49 +01:00
@@ -264,7 +264,7 @@ define('forum/category', [
|
|||||||
|
|
||||||
var topics = $('[component="category/topic"]');
|
var topics = $('[component="category/topic"]');
|
||||||
var afterEl = direction > 0 ? topics.last() : topics.first();
|
var afterEl = direction > 0 ? topics.last() : topics.first();
|
||||||
var after = (parseInt(afterEl.attr('data-index'), 10) || 0) + 1;
|
var after = (parseInt(afterEl.attr('data-index'), 10) || 0) + (direction > 0 ? 1 : 0);
|
||||||
|
|
||||||
loadTopicsAfter(after, direction);
|
loadTopicsAfter(after, direction);
|
||||||
};
|
};
|
||||||
@@ -281,8 +281,7 @@ define('forum/category', [
|
|||||||
cid: ajaxify.data.cid,
|
cid: ajaxify.data.cid,
|
||||||
after: after,
|
after: after,
|
||||||
direction: direction,
|
direction: direction,
|
||||||
author: params.author,
|
query: params,
|
||||||
tag: params.tag,
|
|
||||||
categoryTopicSort: config.categoryTopicSort,
|
categoryTopicSort: config.categoryTopicSort,
|
||||||
}, function (data, done) {
|
}, function (data, done) {
|
||||||
if (data.topics && data.topics.length) {
|
if (data.topics && data.topics.length) {
|
||||||
|
|||||||
@@ -35,17 +35,13 @@ Categories.getCategoryById = function (data, callback) {
|
|||||||
return next(new Error('[[error:invalid-cid]]'));
|
return next(new Error('[[error:invalid-cid]]'));
|
||||||
}
|
}
|
||||||
category = categories[0];
|
category = categories[0];
|
||||||
|
data.category = category;
|
||||||
async.parallel({
|
async.parallel({
|
||||||
topics: function (next) {
|
topics: function (next) {
|
||||||
Categories.getCategoryTopics(data, next);
|
Categories.getCategoryTopics(data, next);
|
||||||
},
|
},
|
||||||
topicCount: function (next) {
|
topicCount: function (next) {
|
||||||
if (Array.isArray(data.set)) {
|
Categories.getTopicCount(data, next);
|
||||||
db.sortedSetIntersectCard(data.set, next);
|
|
||||||
} else {
|
|
||||||
next(null, category.topic_count);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
isIgnored: function (next) {
|
isIgnored: function (next) {
|
||||||
Categories.isIgnored([data.cid], data.uid, next);
|
Categories.isIgnored([data.cid], data.uid, next);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ var async = require('async');
|
|||||||
var db = require('../database');
|
var db = require('../database');
|
||||||
var topics = require('../topics');
|
var topics = require('../topics');
|
||||||
var plugins = require('../plugins');
|
var plugins = require('../plugins');
|
||||||
|
var meta = require('../meta');
|
||||||
|
|
||||||
module.exports = function (Categories) {
|
module.exports = function (Categories) {
|
||||||
Categories.getCategoryTopics = function (data, callback) {
|
Categories.getCategoryTopics = function (data, callback) {
|
||||||
@@ -37,40 +38,52 @@ module.exports = function (Categories) {
|
|||||||
|
|
||||||
Categories.getTopicIds = function (data, callback) {
|
Categories.getTopicIds = function (data, callback) {
|
||||||
var pinnedTids;
|
var pinnedTids;
|
||||||
var pinnedCount;
|
|
||||||
var totalPinnedCount;
|
|
||||||
|
|
||||||
var start = data.start;
|
|
||||||
var stop = data.stop;
|
|
||||||
var set = data.set;
|
|
||||||
|
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function (next) {
|
function (next) {
|
||||||
Categories.getPinnedTids(data.cid, 0, -1, next);
|
Categories.getPinnedTids(data.cid, 0, -1, next);
|
||||||
},
|
},
|
||||||
function (_pinnedTids, next) {
|
function (_pinnedTids, next) {
|
||||||
totalPinnedCount = _pinnedTids.length;
|
var totalPinnedCount = _pinnedTids.length;
|
||||||
|
|
||||||
pinnedTids = _pinnedTids.slice(start, stop === -1 ? undefined : stop + 1);
|
pinnedTids = _pinnedTids.slice(data.start, data.stop === -1 ? undefined : data.stop + 1);
|
||||||
|
|
||||||
pinnedCount = pinnedTids.length;
|
var pinnedCount = pinnedTids.length;
|
||||||
|
|
||||||
var topicsPerPage = stop - start + 1;
|
var topicsPerPage = data.stop - data.start + 1;
|
||||||
|
|
||||||
var normalTidsToGet = Math.max(0, topicsPerPage - pinnedCount);
|
var normalTidsToGet = Math.max(0, topicsPerPage - pinnedCount);
|
||||||
|
|
||||||
if (!normalTidsToGet && stop !== -1) {
|
if (!normalTidsToGet && data.stop !== -1) {
|
||||||
return next(null, []);
|
return next(null, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (plugins.hasListeners('filter:categories.getTopicIds')) {
|
||||||
|
return plugins.fireHook('filter:categories.getTopicIds', {
|
||||||
|
tids: [],
|
||||||
|
data: data,
|
||||||
|
pinnedTids: pinnedTids,
|
||||||
|
allPinnedTids: _pinnedTids,
|
||||||
|
totalPinnedCount: totalPinnedCount,
|
||||||
|
normalTidsToGet: normalTidsToGet,
|
||||||
|
}, function (err, data) {
|
||||||
|
callback(err, data && data.tids);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var set = Categories.buildTopicsSortedSet(data);
|
||||||
|
var reverse = Categories.getSortedSetRangeDirection(data.sort);
|
||||||
|
var start = data.start;
|
||||||
if (start > 0 && totalPinnedCount) {
|
if (start > 0 && totalPinnedCount) {
|
||||||
start -= totalPinnedCount - pinnedCount;
|
start -= totalPinnedCount - pinnedCount;
|
||||||
}
|
}
|
||||||
stop = stop === -1 ? stop : start + normalTidsToGet - 1;
|
|
||||||
|
var stop = data.stop === -1 ? data.stop : start + normalTidsToGet - 1;
|
||||||
|
|
||||||
if (Array.isArray(set)) {
|
if (Array.isArray(set)) {
|
||||||
db[data.reverse ? 'getSortedSetRevIntersect' : 'getSortedSetIntersect']({ sets: set, start: start, stop: stop }, next);
|
db[reverse ? 'getSortedSetRevIntersect' : 'getSortedSetIntersect']({ sets: set, start: start, stop: stop }, next);
|
||||||
} else {
|
} else {
|
||||||
db[data.reverse ? 'getSortedSetRevRange' : 'getSortedSetRange'](set, start, stop, next);
|
db[reverse ? 'getSortedSetRevRange' : 'getSortedSetRange'](set, start, stop, next);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function (normalTids, next) {
|
function (normalTids, next) {
|
||||||
@@ -83,6 +96,54 @@ module.exports = function (Categories) {
|
|||||||
], callback);
|
], callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Categories.getTopicCount = function (data, callback) {
|
||||||
|
if (plugins.hasListeners('filter:categories.getTopicCount')) {
|
||||||
|
return plugins.fireHook('filter:categories.getTopicCount', {
|
||||||
|
topicCount: data.category.topic_count,
|
||||||
|
data: data,
|
||||||
|
}, function (err, data) {
|
||||||
|
callback(err, data && data.topicCount);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var set = Categories.buildTopicsSortedSet(data);
|
||||||
|
if (Array.isArray(set)) {
|
||||||
|
db.sortedSetIntersectCard(set, callback);
|
||||||
|
} else {
|
||||||
|
callback(null, data.category.topic_count);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Categories.buildTopicsSortedSet = function (data) {
|
||||||
|
var cid = data.cid;
|
||||||
|
var set = 'cid:' + cid + ':tids';
|
||||||
|
var sort = data.sort || (data.settings && data.settings.categoryTopicSort) || meta.config.categoryTopicSort || 'newest_to_oldest';
|
||||||
|
|
||||||
|
if (sort === 'most_posts') {
|
||||||
|
set = 'cid:' + cid + ':tids:posts';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.targetUid) {
|
||||||
|
set = 'cid:' + cid + ':uid:' + data.targetUid + ':tids';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.tag) {
|
||||||
|
if (Array.isArray(data.tag)) {
|
||||||
|
set = [set].concat(data.tag.map(function (tag) {
|
||||||
|
return 'tag:' + tag + ':topics';
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
set = [set, 'tag:' + data.tag + ':topics'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return set;
|
||||||
|
};
|
||||||
|
|
||||||
|
Categories.getSortedSetRangeDirection = function (sort) {
|
||||||
|
sort = sort || 'newest_to_oldest';
|
||||||
|
var reverse = sort === 'newest_to_oldest' || sort === 'most_posts';
|
||||||
|
return reverse;
|
||||||
|
};
|
||||||
|
|
||||||
Categories.getAllTopicIds = function (cid, start, stop, callback) {
|
Categories.getAllTopicIds = function (cid, start, stop, callback) {
|
||||||
db.getSortedSetRange(['cid:' + cid + ':tids:pinned', 'cid:' + cid + ':tids'], start, stop, callback);
|
db.getSortedSetRange(['cid:' + cid + ':tids:pinned', 'cid:' + cid + ':tids'], start, stop, callback);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -77,49 +77,27 @@ categoryController.get = function (req, res, callback) {
|
|||||||
topicIndex = 0;
|
topicIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
var set = 'cid:' + cid + ':tids';
|
|
||||||
var reverse = false;
|
|
||||||
// `sort` qs has priority over user setting
|
|
||||||
var sort = req.query.sort || settings.categoryTopicSort;
|
var sort = req.query.sort || settings.categoryTopicSort;
|
||||||
if (sort === 'newest_to_oldest') {
|
|
||||||
reverse = true;
|
|
||||||
} else if (sort === 'most_posts') {
|
|
||||||
reverse = true;
|
|
||||||
set = 'cid:' + cid + ':tids:posts';
|
|
||||||
}
|
|
||||||
|
|
||||||
var start = ((currentPage - 1) * settings.topicsPerPage) + topicIndex;
|
var start = ((currentPage - 1) * settings.topicsPerPage) + topicIndex;
|
||||||
var stop = start + settings.topicsPerPage - 1;
|
var stop = start + settings.topicsPerPage - 1;
|
||||||
|
|
||||||
var payload = {
|
|
||||||
cid: cid,
|
|
||||||
set: set,
|
|
||||||
reverse: reverse,
|
|
||||||
start: start,
|
|
||||||
stop: stop,
|
|
||||||
uid: req.uid,
|
|
||||||
settings: settings,
|
|
||||||
};
|
|
||||||
|
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function (next) {
|
function (next) {
|
||||||
user.getUidByUserslug(req.query.author, next);
|
user.getUidByUserslug(req.query.author, next);
|
||||||
},
|
},
|
||||||
function (uid, next) {
|
function (targetUid, next) {
|
||||||
payload.targetUid = uid;
|
var payload = {
|
||||||
if (uid) {
|
uid: req.uid,
|
||||||
payload.set = 'cid:' + cid + ':uid:' + uid + ':tids';
|
cid: cid,
|
||||||
}
|
start: start,
|
||||||
|
stop: stop,
|
||||||
|
sort: sort,
|
||||||
|
settings: settings,
|
||||||
|
query: req.query,
|
||||||
|
tag: req.query.tag,
|
||||||
|
targetUid: targetUid,
|
||||||
|
};
|
||||||
|
|
||||||
if (req.query.tag) {
|
|
||||||
if (Array.isArray(req.query.tag)) {
|
|
||||||
payload.set = [payload.set].concat(req.query.tag.map(function (tag) {
|
|
||||||
return 'tag:' + tag + ':topics';
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
payload.set = [payload.set, 'tag:' + req.query.tag + ':topics'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
categories.getCategoryById(payload, next);
|
categories.getCategoryById(payload, next);
|
||||||
},
|
},
|
||||||
], next);
|
], next);
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ SocketCategories.loadMore = function (socket, data, callback) {
|
|||||||
if (!data) {
|
if (!data) {
|
||||||
return callback(new Error('[[error:invalid-data]]'));
|
return callback(new Error('[[error:invalid-data]]'));
|
||||||
}
|
}
|
||||||
|
data.query = data.query || {};
|
||||||
var userPrivileges;
|
var userPrivileges;
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function (next) {
|
function (next) {
|
||||||
@@ -70,8 +71,8 @@ SocketCategories.loadMore = function (socket, data, callback) {
|
|||||||
user.getSettings(socket.uid, next);
|
user.getSettings(socket.uid, next);
|
||||||
},
|
},
|
||||||
targetUid: function (next) {
|
targetUid: function (next) {
|
||||||
if (data.author) {
|
if (data.query.author) {
|
||||||
user.getUidByUserslug(data.author, next);
|
user.getUidByUserslug(data.query.author, next);
|
||||||
} else {
|
} else {
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
@@ -84,44 +85,28 @@ SocketCategories.loadMore = function (socket, data, callback) {
|
|||||||
return callback(new Error('[[error:no-privileges]]'));
|
return callback(new Error('[[error:no-privileges]]'));
|
||||||
}
|
}
|
||||||
var infScrollTopicsPerPage = 20;
|
var infScrollTopicsPerPage = 20;
|
||||||
var set = 'cid:' + data.cid + ':tids';
|
var sort = data.sort || data.categoryTopicSort;
|
||||||
var reverse = false;
|
|
||||||
|
|
||||||
if (data.categoryTopicSort === 'newest_to_oldest') {
|
|
||||||
reverse = true;
|
|
||||||
} else if (data.categoryTopicSort === 'most_posts') {
|
|
||||||
reverse = true;
|
|
||||||
set = 'cid:' + data.cid + ':tids:posts';
|
|
||||||
}
|
|
||||||
|
|
||||||
var start = Math.max(0, parseInt(data.after, 10));
|
var start = Math.max(0, parseInt(data.after, 10));
|
||||||
|
|
||||||
if (data.direction === -1) {
|
if (data.direction === -1) {
|
||||||
start -= reverse ? infScrollTopicsPerPage : -infScrollTopicsPerPage;
|
start -= infScrollTopicsPerPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
var stop = start + infScrollTopicsPerPage - 1;
|
var stop = start + infScrollTopicsPerPage - 1;
|
||||||
|
|
||||||
start = Math.max(0, start);
|
start = Math.max(0, start);
|
||||||
stop = Math.max(0, stop);
|
stop = Math.max(0, stop);
|
||||||
|
|
||||||
if (results.targetUid) {
|
|
||||||
set = 'cid:' + data.cid + ':uid:' + results.targetUid + ':tids';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.tag) {
|
|
||||||
set = [set, 'tag:' + data.tag + ':topics'];
|
|
||||||
}
|
|
||||||
|
|
||||||
categories.getCategoryTopics({
|
categories.getCategoryTopics({
|
||||||
|
uid: socket.uid,
|
||||||
cid: data.cid,
|
cid: data.cid,
|
||||||
set: set,
|
|
||||||
reverse: reverse,
|
|
||||||
start: start,
|
start: start,
|
||||||
stop: stop,
|
stop: stop,
|
||||||
uid: socket.uid,
|
sort: sort,
|
||||||
targetUid: results.targetUid,
|
|
||||||
settings: results.settings,
|
settings: results.settings,
|
||||||
|
query: data.query,
|
||||||
|
tag: data.query.tag,
|
||||||
|
targetUid: results.targetUid,
|
||||||
}, next);
|
}, next);
|
||||||
},
|
},
|
||||||
function (data, next) {
|
function (data, next) {
|
||||||
|
|||||||
@@ -27,7 +27,12 @@ module.exports = function (Topics) {
|
|||||||
async.waterfall([
|
async.waterfall([
|
||||||
function (next) {
|
function (next) {
|
||||||
if (cid) {
|
if (cid) {
|
||||||
categories.getTopicIds(cid, 'cid:' + cid + ':tids', true, 0, 199, next);
|
categories.getTopicIds({
|
||||||
|
cid: cid,
|
||||||
|
start: 0,
|
||||||
|
stop: 199,
|
||||||
|
sort: 'newest_to_oldest',
|
||||||
|
}, next);
|
||||||
} else {
|
} else {
|
||||||
db.getSortedSetRevRange('topics:recent', 0, 199, next);
|
db.getSortedSetRevRange('topics:recent', 0, 199, next);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,7 +73,11 @@ module.exports = function (Topics) {
|
|||||||
Topics.getTopicField(tid, 'cid', next);
|
Topics.getTopicField(tid, 'cid', next);
|
||||||
},
|
},
|
||||||
function (cid, next) {
|
function (cid, next) {
|
||||||
categories.getTopicIds(cid, 'cid:' + cid + ':tids', true, 0, 9, next);
|
categories.getTopicIds({
|
||||||
|
cid: cid,
|
||||||
|
start: 0,
|
||||||
|
stop: 9,
|
||||||
|
}, next);
|
||||||
},
|
},
|
||||||
], callback);
|
], callback);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,8 +54,6 @@ 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,
|
||||||
stop: -1,
|
stop: -1,
|
||||||
uid: 0,
|
uid: 0,
|
||||||
@@ -103,11 +101,10 @@ 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,
|
||||||
|
sort: 'oldest-to-newest',
|
||||||
}, function (err, result) {
|
}, function (err, result) {
|
||||||
assert.equal(err, null);
|
assert.equal(err, null);
|
||||||
|
|
||||||
@@ -123,12 +120,11 @@ 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,
|
||||||
targetUid: 1,
|
targetUid: 1,
|
||||||
|
sort: 'oldest-to-newest',
|
||||||
}, function (err, result) {
|
}, function (err, result) {
|
||||||
assert.equal(err, null);
|
assert.equal(err, null);
|
||||||
assert(Array.isArray(result.topics));
|
assert(Array.isArray(result.topics));
|
||||||
@@ -226,7 +222,14 @@ describe('Categories', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should load more topics', function (done) {
|
it('should load more topics', function (done) {
|
||||||
socketCategories.loadMore({ uid: posterUid }, { cid: categoryObj.cid, after: 0, author: 'poster', tag: 'nodebb' }, function (err, data) {
|
socketCategories.loadMore({ uid: posterUid }, {
|
||||||
|
cid: categoryObj.cid,
|
||||||
|
after: 0,
|
||||||
|
query: {
|
||||||
|
author: 'poster',
|
||||||
|
tag: 'nodebb',
|
||||||
|
},
|
||||||
|
}, function (err, data) {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
assert(Array.isArray(data.topics));
|
assert(Array.isArray(data.topics));
|
||||||
assert.equal(data.topics[0].user.username, 'poster');
|
assert.equal(data.topics[0].user.username, 'poster');
|
||||||
@@ -244,7 +247,7 @@ describe('Categories', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should load page count', function (done) {
|
it('should load topic count', function (done) {
|
||||||
socketCategories.getTopicCount({ uid: posterUid }, categoryObj.cid, function (err, topicCount) {
|
socketCategories.getTopicCount({ uid: posterUid }, categoryObj.cid, function (err, topicCount) {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
assert.equal(topicCount, 2);
|
assert.equal(topicCount, 2);
|
||||||
@@ -680,4 +683,31 @@ describe('Categories', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('getTopicIds', function () {
|
||||||
|
var plugins = require('../src/plugins');
|
||||||
|
it('should get topic ids with filter', function (done) {
|
||||||
|
function method(data, callback) {
|
||||||
|
data.tids = [1, 2, 3];
|
||||||
|
callback(null, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins.registerHook('my-test-plugin', {
|
||||||
|
hook: 'filter:categories.getTopicIds',
|
||||||
|
method: method,
|
||||||
|
});
|
||||||
|
|
||||||
|
Categories.getTopicIds({
|
||||||
|
cid: categoryObj.cid,
|
||||||
|
start: 0,
|
||||||
|
stop: 19,
|
||||||
|
}, function (err, tids) {
|
||||||
|
assert.ifError(err);
|
||||||
|
assert.deepEqual(tids, [1, 2, 3]);
|
||||||
|
plugins.unregisterHook('my-test-plugin', 'filter:categories.getTopicIds', method);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user