properly filter /unread /recent /popular /top ()

* feat: add failing test for pagination

* feat: test

* fix: redis tests

* refactor: remove logs

* fix: add new test

* feat: make sortedSetRangeByScore work with keys on redis

* fix: hardcoded set name

* feat: show topics from readable categories on recent/popular/top

* feat: rewrite unread topics

respect watched categories and followed topics

* fix: term + watched
v1.18.x
Barış Soner Uşaklı committed by GitHub
parent 17437897f9
commit 310c6fd33f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -77,7 +77,7 @@ Categories.getAllCategories = async function (uid) {
};
Categories.getCidsByPrivilege = async function (set, uid, privilege) {
const cids = await Categories.getAllCidsFromSet('categories:cid');
const cids = await Categories.getAllCidsFromSet(set);
return await privileges.categories.filterCids(privilege, cids, uid);
};

@ -213,7 +213,7 @@ helpers.getCategories = async function (set, uid, privilege, selectedCid) {
helpers.getCategoriesByStates = async function (uid, selectedCid, states) {
let cids = await user.getCategoriesByStates(uid, states);
cids = await privileges.categories.filterCids('read', cids, uid);
cids = await privileges.categories.filterCids('topics:read', cids, uid);
return await getCategoryData(cids, uid, selectedCid);
};

@ -48,7 +48,7 @@ recentController.getData = async function (req, url, sort) {
const stop = start + settings.topicsPerPage - 1;
const data = await topics.getSortedTopics({
cids: cid,
cids: cid || categoryData.categories.map(c => c.cid),
uid: req.uid,
start: start,
stop: stop,

@ -11,28 +11,28 @@ module.exports = function (module) {
require('./sorted/intersect')(module);
module.getSortedSetRange = async function (key, start, stop) {
return await sortedSetRange('zrange', key, start, stop, false);
return await sortedSetRange('zrange', key, start, stop, '-inf', '+inf', false);
};
module.getSortedSetRevRange = async function (key, start, stop) {
return await sortedSetRange('zrevrange', key, start, stop, false);
return await sortedSetRange('zrevrange', key, start, stop, '-inf', '+inf', false);
};
module.getSortedSetRangeWithScores = async function (key, start, stop) {
return await sortedSetRange('zrange', key, start, stop, true);
return await sortedSetRange('zrange', key, start, stop, '-inf', '+inf', true);
};
module.getSortedSetRevRangeWithScores = async function (key, start, stop) {
return await sortedSetRange('zrevrange', key, start, stop, true);
return await sortedSetRange('zrevrange', key, start, stop, '-inf', '+inf', true);
};
async function sortedSetRange(method, key, start, stop, withScores) {
async function sortedSetRange(method, key, start, stop, min, max, withScores) {
if (Array.isArray(key)) {
if (!key.length) {
return [];
}
const batch = module.client.batch();
key.forEach(key => batch[method]([key, 0, stop, 'WITHSCORES']));
key.forEach(key => batch[method](genParams(method, key, 0, stop, min, max, true)));
const data = await helpers.execBatch(batch);
const batchData = data.map(setData => helpers.zsetToObjectArray(setData));
@ -48,11 +48,7 @@ module.exports = function (module) {
return objects;
}
var params = [key, start, stop];
if (withScores) {
params.push('WITHSCORES');
}
const params = genParams(method, key, start, stop, min, max, withScores);
const data = await module.client.async[method](params);
if (!withScores) {
return data;
@ -61,25 +57,46 @@ module.exports = function (module) {
return objects;
}
function genParams(method, key, start, stop, min, max, withScores) {
const params = {
zrevrange: [key, start, stop],
zrange: [key, start, stop],
zrangebyscore: [key, min, max],
zrevrangebyscore: [key, max, min],
};
if (withScores) {
params[method].push('WITHSCORES');
}
if (method === 'zrangebyscore' || method === 'zrevrangebyscore') {
const count = stop !== -1 ? stop - start + 1 : stop;
params[method].push('LIMIT', start, count);
}
return params[method];
}
module.getSortedSetRangeByScore = async function (key, start, count, min, max) {
return await module.client.async.zrangebyscore([key, min, max, 'LIMIT', start, count]);
return await sortedSetRangeByScore('zrangebyscore', key, start, count, min, max, false);
};
module.getSortedSetRevRangeByScore = async function (key, start, count, max, min) {
return await module.client.async.zrevrangebyscore([key, max, min, 'LIMIT', start, count]);
return await sortedSetRangeByScore('zrevrangebyscore', key, start, count, min, max, false);
};
module.getSortedSetRangeByScoreWithScores = async function (key, start, count, min, max) {
return await sortedSetRangeByScoreWithScores('zrangebyscore', key, start, count, min, max);
return await sortedSetRangeByScore('zrangebyscore', key, start, count, min, max, true);
};
module.getSortedSetRevRangeByScoreWithScores = async function (key, start, count, max, min) {
return await sortedSetRangeByScoreWithScores('zrevrangebyscore', key, start, count, max, min);
return await sortedSetRangeByScore('zrevrangebyscore', key, start, count, min, max, true);
};
async function sortedSetRangeByScoreWithScores(method, key, start, count, min, max) {
const data = await module.client.async[method]([key, min, max, 'WITHSCORES', 'LIMIT', start, count]);
return helpers.zsetToObjectArray(data);
async function sortedSetRangeByScore(method, key, start, count, min, max, withScores) {
if (parseInt(count, 10) === 0) {
return [];
}
const stop = (parseInt(count, 10) === -1) ? -1 : (start + count - 1);
return await sortedSetRange(method, key, start, stop, min, max, withScores);
}
module.sortedSetCount = async function (key, min, max) {

@ -103,9 +103,7 @@ module.exports = function (privileges) {
cids = _.uniq(cids);
const results = await privileges.categories.getBase(privilege, cids, uid);
return cids.filter(function (cid, index) {
return !!cid && !results.categories[index].disabled && (results.allowedTo[index] || results.isAdmin);
});
return cids.filter((cid, index) => !!cid && !results.categories[index].disabled && (results.allowedTo[index] || results.isAdmin));
};
privileges.categories.getBase = async function (privilege, cids, uid) {

@ -71,10 +71,7 @@ module.exports = function (privileges) {
let cids = _.uniq(topicsData.map(topic => topic.cid));
const results = await privileges.categories.getBase(privilege, cids, uid);
cids = cids.filter(function (cid, index) {
return !results.categories[index].disabled &&
(results.allowedTo[index] || results.isAdmin);
});
cids = cids.filter((cid, index) => !results.categories[index].disabled && (results.allowedTo[index] || results.isAdmin));
const cidsSet = new Set(cids);

@ -1,5 +1,6 @@
'use strict';
const db = require('../../database');
const user = require('../../user');
const topics = require('../../topics');
@ -53,7 +54,7 @@ module.exports = function (SocketTopics) {
throw new Error('[[error:no-privileges]]');
}
const isAdmin = await user.isAdministrator(socket.uid);
const now = Date.now();
await Promise.all(tids.map(async (tid) => {
const topicData = await topics.getTopicFields(tid, ['tid', 'cid']);
if (!topicData.tid) {
@ -64,7 +65,8 @@ module.exports = function (SocketTopics) {
throw new Error('[[error:no-privileges]]');
}
await topics.markAsUnreadForAll(tid);
await topics.updateRecent(tid, Date.now());
await topics.updateRecent(tid, now);
await db.sortedSetAdd('cid:' + topicData.cid + ':tids:lastposttime', now, tid);
}));
topics.pushUnreadCount(socket.uid);
};

@ -134,8 +134,7 @@ module.exports = function (Topics) {
return [];
}
const scores = await db.sortedSetScores('uid:' + uid + ':followed_tids', tids);
tids = tids.filter((tid, index) => tid && !!scores[index]);
return tids;
return tids.filter((tid, index) => tid && !!scores[index]);
};
Topics.filterNotIgnoredTids = async function (tids, uid) {
@ -143,8 +142,7 @@ module.exports = function (Topics) {
return tids;
}
const scores = await db.sortedSetScores('uid:' + uid + ':ignored_tids', tids);
tids = tids.filter((tid, index) => tid && !scores[index]);
return tids;
return tids.filter((tid, index) => tid && !scores[index]);
};
Topics.notifyFollowers = async function (postData, exceptUid) {

@ -33,29 +33,32 @@ module.exports = function (Topics) {
async function getTids(params) {
let tids = [];
if (params.term === 'alltime') {
if (params.cids) {
tids = await getCidTids(params.cids, params.sort);
} else {
tids = await db.getSortedSetRevRange('topics:' + params.sort, 0, 199);
if (params.term !== 'alltime') {
tids = await Topics.getLatestTidsFromSet('topics:tid', 0, -1, params.term);
if (params.filter === 'watched') {
tids = await Topics.filterWatchedTids(tids, params.uid);
}
} else if (params.filter === 'watched') {
tids = await db.getSortedSetRevRange('uid:' + params.uid + ':followed_tids', 0, -1);
} else if (params.cids) {
tids = await getCidTids(params);
} else {
tids = await Topics.getLatestTidsFromSet('topics:tid', 0, -1, params.term);
tids = await db.getSortedSetRevRange('topics:' + params.sort, 0, 199);
}
if (params.term !== 'alltime' || params.cids || params.floatPinned) {
if (params.term !== 'alltime' || params.cids || params.filter === 'watched' || params.floatPinned) {
tids = await sortTids(tids, params);
}
return await filterTids(tids, params);
return await filterTids(tids.slice(0, 200), params);
}
async function getCidTids(cids, sort) {
async function getCidTids(params) {
const sets = [];
const pinnedSets = [];
cids.forEach(function (cid) {
if (sort === 'recent') {
params.cids.forEach(function (cid) {
if (params.sort === 'recent') {
sets.push('cid:' + cid + ':tids');
} else {
sets.push('cid:' + cid + ':tids' + (sort ? ':' + sort : ''));
sets.push('cid:' + cid + ':tids' + (params.sort ? ':' + params.sort : ''));
}
pinnedSets.push('cid:' + cid + ':tids:pinned');
});
@ -115,9 +118,7 @@ module.exports = function (Topics) {
const filter = params.filter;
const uid = params.uid;
if (filter === 'watched') {
tids = await Topics.filterWatchedTids(tids, uid);
} else if (filter === 'new') {
if (filter === 'new') {
tids = await Topics.filterNewTids(tids, uid);
} else if (filter === 'unreplied') {
tids = await Topics.filterUnrepliedTids(tids);
@ -130,7 +131,7 @@ module.exports = function (Topics) {
const topicCids = _.uniq(topicData.map(topic => topic.cid)).filter(Boolean);
async function getIgnoredCids() {
if (filter === 'watched' || meta.config.disableRecentCategoryFilter) {
if (params.cids || filter === 'watched' || meta.config.disableRecentCategoryFilter) {
return [];
}
return await categories.isIgnored(topicCids, uid);
@ -144,9 +145,7 @@ module.exports = function (Topics) {
topicData = filtered;
const cids = params.cids && params.cids.map(String);
tids = topicData.filter(function (topic) {
return topic && topic.cid && !isCidIgnored[topic.cid] && (!cids || (cids.length && cids.includes(topic.cid.toString())));
}).map(topic => topic.tid);
tids = topicData.filter(t => t && t.cid && !isCidIgnored[t.cid] && (!cids || cids.includes(String(t.cid)))).map(t => t.tid);
const result = await plugins.fireHook('filter:topics.filterSortedTids', { tids: tids, params: params });
return result.tids;

@ -1,18 +1,18 @@
'use strict';
var async = require('async');
var _ = require('lodash');
var db = require('../database');
var user = require('../user');
var posts = require('../posts');
var notifications = require('../notifications');
var categories = require('../categories');
var privileges = require('../privileges');
var meta = require('../meta');
var utils = require('../utils');
var plugins = require('../plugins');
const async = require('async');
const _ = require('lodash');
const db = require('../database');
const user = require('../user');
const posts = require('../posts');
const notifications = require('../notifications');
const categories = require('../categories');
const privileges = require('../privileges');
const meta = require('../meta');
const utils = require('../utils');
const plugins = require('../plugins');
module.exports = function (Topics) {
Topics.getTotalUnread = async function (uid, filter) {
@ -22,7 +22,7 @@ module.exports = function (Topics) {
};
Topics.getUnreadTopics = async function (params) {
var unreadTopics = {
const unreadTopics = {
showSelect: true,
nextStart: 0,
topics: [],
@ -57,51 +57,18 @@ module.exports = function (Topics) {
Topics.getUnreadData = async function (params) {
const uid = parseInt(params.uid, 10);
const counts = {
'': 0,
new: 0,
watched: 0,
unreplied: 0,
};
const noUnreadData = {
tids: [],
counts: counts,
tidsByFilter: {
'': [],
new: [],
watched: [],
unreplied: [],
},
};
if (uid <= 0) {
return noUnreadData;
}
params.filter = params.filter || '';
var cutoff = params.cutoff || Topics.unreadCutoff();
if (params.cid && !Array.isArray(params.cid)) {
params.cid = [params.cid];
}
const [ignoredTids, recentTids, userScores, tids_unread] = await Promise.all([
user.getIgnoredTids(uid, 0, -1),
db.getSortedSetRevRangeByScoreWithScores('topics:recent', 0, -1, '+inf', cutoff),
db.getSortedSetRevRangeByScoreWithScores('uid:' + uid + ':tids_read', 0, -1, '+inf', cutoff),
db.getSortedSetRevRangeWithScores('uid:' + uid + ':tids_unread', 0, -1),
]);
if (recentTids && !recentTids.length && !tids_unread.length) {
return noUnreadData;
const data = await getTids(params);
if (!data.tids && !data.tids.length) {
return data;
}
const data = await filterTopics(params, {
ignoredTids: ignoredTids,
recentTids: recentTids,
userScores: userScores,
tids_unread: tids_unread,
});
const result = await plugins.fireHook('filter:topics.getUnreadTids', {
uid: uid,
tids: data.tids,
@ -113,83 +80,69 @@ module.exports = function (Topics) {
return result;
};
async function filterTopics(params, results) {
const counts = {
'': 0,
new: 0,
watched: 0,
unreplied: 0,
};
const tidsByFilter = {
'': [],
new: [],
watched: [],
unreplied: [],
};
async function getTids(params) {
const counts = { '': 0, new: 0, watched: 0, unreplied: 0 };
const tidsByFilter = { '': [], new: [], watched: [], unreplied: [] };
var userRead = {};
results.userScores.forEach(function (userItem) {
userRead[userItem.value] = userItem.score;
});
if (params.uid <= 0) {
return { counts: counts, tids: [], tidsByFilter: tidsByFilter };
}
results.recentTids = results.recentTids.concat(results.tids_unread);
results.recentTids.sort(function (a, b) {
return b.score - a.score;
});
const cutoff = params.cutoff || Topics.unreadCutoff();
var tids = results.recentTids.filter(function (recentTopic) {
if (results.ignoredTids.includes(String(recentTopic.value))) {
return false;
}
return !userRead[recentTopic.value] || recentTopic.score > userRead[recentTopic.value];
});
const [followedTids, ignoredTids, recentTids, userScores, tids_unread] = await Promise.all([
getFollowedTids(params),
user.getIgnoredTids(params.uid, 0, -1),
getRecentTids(params),
db.getSortedSetRevRangeByScoreWithScores('uid:' + params.uid + ':tids_read', 0, -1, '+inf', cutoff),
db.getSortedSetRevRangeWithScores('uid:' + params.uid + ':tids_unread', 0, -1),
]);
tids = _.uniq(tids.map(topic => topic.value));
const userReadTime = _.mapValues(_.keyBy(userScores, 'value'), 'score');
const isTopicsFollowed = _.mapValues(_.keyBy(followedTids, 'value'), 'score');
var cid = params.cid;
var uid = params.uid;
var cids;
var topicData;
const unreadTopics = _.unionWith(recentTids, followedTids.concat(tids_unread), (a, b) => a.value === b.value)
.filter(t => !ignoredTids.includes(t.value) && (!userReadTime[t.value] || t.score > userReadTime[t.value]))
.sort((a, b) => b.score - a.score);
tids = tids.slice(0, 200);
let tids = _.uniq(unreadTopics.map(topic => topic.value)).slice(0, 200);
if (!tids.length) {
return { counts: counts, tids: tids, tidsByFilter: tidsByFilter };
}
const blockedUids = await user.blocks.list(uid);
const blockedUids = await user.blocks.list(params.uid);
tids = await filterTidsThatHaveBlockedPosts({
uid: uid,
uid: params.uid,
tids: tids,
blockedUids: blockedUids,
recentTids: results.recentTids,
recentTids: recentTids,
});
topicData = await Topics.getTopicsFields(tids, ['tid', 'cid', 'uid', 'postcount']);
cids = _.uniq(topicData.map(topic => topic.cid)).filter(Boolean);
const topicData = await Topics.getTopicsFields(tids, ['tid', 'cid', 'uid', 'postcount']);
const topicCids = _.uniq(topicData.map(topic => topic.cid)).filter(Boolean);
const [isTopicsFollowed, categoryWatchState, readCids] = await Promise.all([
db.sortedSetScores('uid:' + uid + ':followed_tids', tids),
categories.getWatchState(cids, uid),
privileges.categories.filterCids('read', cids, uid),
const [categoryWatchState, readCids] = await Promise.all([
categories.getWatchState(topicCids, params.uid),
privileges.categories.filterCids('topics:read', topicCids, params.uid),
]);
cid = cid && cid.map(String);
const filterCids = params.cid && params.cid.map(String);
const readableCids = readCids.map(String);
const userCidState = _.zipObject(cids, categoryWatchState);
const userCidState = _.zipObject(topicCids, categoryWatchState);
topicData.forEach(function (topic, index) {
function cidMatch(topicCid) {
return (!cid || (cid.length && cid.includes(String(topicCid)))) && readableCids.includes(String(topicCid));
topicData.forEach(function (topic) {
function cidMatch() {
return (!filterCids || (filterCids.length && filterCids.includes(String(topic.cid)))) && readableCids.includes(String(topic.cid));
}
if (topic && topic.cid && cidMatch(topic.cid) && !blockedUids.includes(parseInt(topic.uid, 10))) {
topic.tid = parseInt(topic.tid, 10);
if ((isTopicsFollowed[index] || userCidState[topic.cid] === categories.watchStates.watching)) {
if (topic && topic.cid && cidMatch() && !blockedUids.includes(topic.uid)) {
if (isTopicsFollowed[topic.tid] || userCidState[topic.cid] === categories.watchStates.watching) {
tidsByFilter[''].push(topic.tid);
}
if (isTopicsFollowed[index]) {
if (isTopicsFollowed[topic.tid]) {
tidsByFilter.watched.push(topic.tid);
}
@ -197,11 +150,12 @@ module.exports = function (Topics) {
tidsByFilter.unreplied.push(topic.tid);
}
if (!userRead[topic.tid]) {
if (!userReadTime[topic.tid]) {
tidsByFilter.new.push(topic.tid);
}
}
});
counts[''] = tidsByFilter[''].length;
counts.watched = tidsByFilter.watched.length;
counts.unreplied = tidsByFilter.unreplied.length;
@ -214,6 +168,25 @@ module.exports = function (Topics) {
};
}
async function getRecentTids(params) {
if (params.filter === 'watched') {
return [];
}
const cutoff = params.cutoff || Topics.unreadCutoff();
const cids = params.cid || await user.getWatchedCategories(params.uid);
const keys = cids.map(cid => 'cid:' + cid + ':tids:lastposttime');
return await db.getSortedSetRevRangeByScoreWithScores(keys, 0, -1, '+inf', cutoff);
}
async function getFollowedTids(params) {
const tids = await db.getSortedSetRevRange('uid:' + params.uid + ':followed_tids', 0, -1);
const scores = await db.sortedSetScores('topics:recent', tids);
const cutoff = params.cutoff || Topics.unreadCutoff();
const data = tids.map((tid, index) => ({ value: tid, score: scores[index] }));
return data.filter(item => item.score > cutoff);
}
async function filterTidsThatHaveBlockedPosts(params) {
if (!params.blockedUids.length) {
return params.tids;
@ -234,14 +207,14 @@ module.exports = function (Topics) {
}
async function doesTidHaveUnblockedUnreadPosts(tid, params) {
var userLastReadTimestamp = params.userLastReadTimestamp;
const userLastReadTimestamp = params.userLastReadTimestamp;
if (!userLastReadTimestamp) {
return true;
}
var start = 0;
var count = 3;
var done = false;
var hasUnblockedUnread = params.topicTimestamp > userLastReadTimestamp;
let start = 0;
const count = 3;
let done = false;
let hasUnblockedUnread = params.topicTimestamp > userLastReadTimestamp;
if (!params.blockedUids.length) {
return hasUnblockedUnread;
}
@ -252,9 +225,7 @@ module.exports = function (Topics) {
return hasUnblockedUnread;
}
let postData = await posts.getPostsFields(pidsSinceLastVisit, ['pid', 'uid']);
postData = postData.filter(function (post) {
return !params.blockedUids.includes(parseInt(post.uid, 10));
});
postData = postData.filter(post => !params.blockedUids.includes(parseInt(post.uid, 10)));
done = postData.length > 0;
hasUnblockedUnread = postData.length > 0;
@ -295,23 +266,21 @@ module.exports = function (Topics) {
db.sortedSetScores('uid:' + uid + ':tids_read', tids),
]);
tids = tids.filter(function (tid, index) {
return topicScores[index] && (!userScores[index] || userScores[index] < topicScores[index]);
});
tids = tids.filter((tid, index) => topicScores[index] && (!userScores[index] || userScores[index] < topicScores[index]));
if (!tids.length) {
return false;
}
var now = Date.now();
var scores = tids.map(() => now);
const now = Date.now();
const scores = tids.map(() => now);
const [topicData] = await Promise.all([
Topics.getTopicsFields(tids, ['cid']),
db.sortedSetAdd('uid:' + uid + ':tids_read', scores, tids),
db.sortedSetRemove('uid:' + uid + ':tids_unread', tids),
]);
var cids = _.uniq(topicData.map(t => t && t.cid).filter(Boolean));
const cids = _.uniq(topicData.map(t => t && t.cid).filter(Boolean));
await categories.markAsRead(cids, uid);
plugins.fireHook('action:topics.markAsRead', { uid: uid, tids: tids });
@ -350,9 +319,9 @@ module.exports = function (Topics) {
user.blocks.list(uid),
]);
var cutoff = Topics.unreadCutoff();
var result = tids.map(function (tid, index) {
var read = !tids_unread[index] &&
const cutoff = Topics.unreadCutoff();
const result = tids.map(function (tid, index) {
const read = !tids_unread[index] &&
(topicScores[index] < cutoff ||
!!(userScores[index] && userScores[index] >= topicScores[index]));
return { tid: tid, read: read, index: index };

@ -227,22 +227,11 @@ describe('Sorted Set methods', function () {
});
});
it('should return duplicates if two sets have same elements', function (done) {
async.waterfall([
function (next) {
db.sortedSetAdd('dupezset1', [1, 2], ['value 1', 'value 2'], next);
},
function (next) {
db.sortedSetAdd('dupezset2', [2, 3], ['value 2', 'value 3'], next);
},
function (next) {
db.getSortedSetRange(['dupezset1', 'dupezset2'], 0, -1, next);
},
function (data, next) {
assert.deepStrictEqual(data, ['value 1', 'value 2', 'value 2', 'value 3']);
next();
},
], done);
it('should return duplicates if two sets have same elements', async function () {
await db.sortedSetAdd('dupezset1', [1, 2], ['value 1', 'value 2']);
await db.sortedSetAdd('dupezset2', [2, 3], ['value 2', 'value 3']);
const data = await db.getSortedSetRange(['dupezset1', 'dupezset2'], 0, -1);
assert.deepStrictEqual(data, ['value 1', 'value 2', 'value 2', 'value 3']);
});
it('should return correct number of elements', async function () {
@ -405,6 +394,15 @@ describe('Sorted Set methods', function () {
done();
});
});
it('should work with an array of keys', async function () {
await db.sortedSetAddBulk([
['byScoreWithScoresKeys1', 1, 'value1'],
['byScoreWithScoresKeys2', 2, 'value2'],
]);
const data = await db.getSortedSetRevRangeByScoreWithScores(['byScoreWithScoresKeys1', 'byScoreWithScoresKeys2'], 0, -1, 5, -5);
assert.deepStrictEqual(data, [{ value: 'value2', score: 2 }, { value: 'value1', score: 1 }]);
});
});
describe('sortedSetCount()', function () {

@ -1190,14 +1190,14 @@ describe('Topic\'s', function () {
topic: function (next) {
topics.post({ uid: topic.userId, title: 'unread topic', content: 'unread topic content', cid: topic.categoryId }, next);
},
user: function (next) {
joeUid: function (next) {
User.create({ username: 'regularJoe' }, next);
},
}, function (err, results) {
assert.ifError(err);
tid = results.topic.topicData.tid;
mainPid = results.topic.postData.pid;
uid = results.user;
uid = results.joeUid;
done();
});
});
@ -1385,7 +1385,7 @@ describe('Topic\'s', function () {
},
function (category, next) {
privateCid = category.cid;
privileges.categories.rescind(['read'], category.cid, 'registered-users', next);
privileges.categories.rescind(['topics:read'], category.cid, 'registered-users', next);
},
function (next) {
topics.post({ uid: adminUid, title: 'topic in private category', content: 'registered-users cant see this', cid: privateCid }, next);
@ -1414,7 +1414,7 @@ describe('Topic\'s', function () {
},
function (category, next) {
ignoredCid = category.cid;
privileges.categories.rescind(['read'], category.cid, 'registered-users', next);
privileges.categories.rescind(['topics:read'], category.cid, 'registered-users', next);
},
function (next) {
topics.post({ uid: adminUid, title: 'topic in private category', content: 'registered-users cant see this', cid: ignoredCid }, next);

Loading…
Cancel
Save