mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-01 11:35:55 +01:00
* feat: add upgrade script to give mods privs * feat: give all privileges when making a moderator * feat: remove implicit privs * feat: give global mods default privs * feat: more priv fixes * feat: use lodash * fix: remove implicit mod priv from topic delete * fix: more privs * fix: posts.canEdit * fix: canDelete and canEdit * fix: tests, remove console.log * feat: shorter functions * feat: add tests * fix: uids * fix: redis random test fail
This commit is contained in:
committed by
GitHub
parent
ebb32e7891
commit
035f624758
@@ -89,7 +89,7 @@ define('admin/manage/admins-mods', ['translator', 'benchpress', 'autocomplete'],
|
||||
var cid = $(ev.target).attr('data-cid');
|
||||
socket.emit('admin.categories.setPrivilege', {
|
||||
cid: cid,
|
||||
privilege: ['moderate'],
|
||||
privilege: ajaxify.data.allPrivileges,
|
||||
set: true,
|
||||
member: ui.item.user.uid,
|
||||
}, function (err) {
|
||||
@@ -120,7 +120,7 @@ define('admin/manage/admins-mods', ['translator', 'benchpress', 'autocomplete'],
|
||||
if (confirm) {
|
||||
socket.emit('admin.categories.setPrivilege', {
|
||||
cid: cid,
|
||||
privilege: ['moderate'],
|
||||
privilege: ajaxify.data.allPrivileges,
|
||||
set: false,
|
||||
member: uid,
|
||||
}, function (err) {
|
||||
|
||||
@@ -68,6 +68,11 @@ module.exports = function (Categories) {
|
||||
'posts:downvote',
|
||||
'topics:delete',
|
||||
];
|
||||
const modPrivileges = defaultPrivileges.concat([
|
||||
'posts:view_deleted',
|
||||
'purge',
|
||||
'moderate',
|
||||
]);
|
||||
|
||||
async.series([
|
||||
async.apply(db.setObject, 'category:' + category.cid, category),
|
||||
@@ -78,7 +83,8 @@ module.exports = function (Categories) {
|
||||
Categories.parseDescription(category.cid, category.description, next);
|
||||
},
|
||||
async.apply(db.sortedSetsAdd, ['categories:cid', 'cid:' + parentCid + ':children'], category.order, category.cid),
|
||||
async.apply(privileges.categories.give, defaultPrivileges, category.cid, ['administrators', 'registered-users']),
|
||||
async.apply(privileges.categories.give, defaultPrivileges, category.cid, 'registered-users'),
|
||||
async.apply(privileges.categories.give, modPrivileges, category.cid, ['administrators', 'Global Moderators']),
|
||||
async.apply(privileges.categories.give, ['find', 'read', 'topics:read'], category.cid, ['guests', 'spiders']),
|
||||
], next);
|
||||
},
|
||||
|
||||
@@ -4,6 +4,7 @@ var async = require('async');
|
||||
|
||||
var groups = require('../../groups');
|
||||
var categories = require('../../categories');
|
||||
var privileges = require('../../privileges');
|
||||
|
||||
var AdminsMods = module.exports;
|
||||
|
||||
@@ -23,6 +24,7 @@ AdminsMods.get = function (req, res, next) {
|
||||
}, next);
|
||||
},
|
||||
function (results) {
|
||||
results.allPrivileges = privileges.userPrivilegeList;
|
||||
res.render('admin/manage/admins-mods', results);
|
||||
},
|
||||
], next);
|
||||
|
||||
@@ -397,6 +397,9 @@ function giveGlobalPrivileges(next) {
|
||||
function (next) {
|
||||
privileges.global.give(defaultPrivileges, 'registered-users', next);
|
||||
},
|
||||
function (next) {
|
||||
privileges.global.give(defaultPrivileges.concat(['ban', 'upload:post:file']), 'Global Moderators', next);
|
||||
},
|
||||
function (next) {
|
||||
privileges.global.give(['view:users', 'view:tags', 'view:groups'], 'guests', next);
|
||||
},
|
||||
|
||||
@@ -28,9 +28,7 @@ module.exports = function (Posts) {
|
||||
},
|
||||
function (_postData, next) {
|
||||
postData = _postData;
|
||||
tids = _.uniq(postData.map(function (post) {
|
||||
return post && post.tid;
|
||||
}).filter(Boolean));
|
||||
tids = _.uniq(postData.map(post => post && post.tid).filter(Boolean));
|
||||
|
||||
topics.getTopicsFields(tids, ['cid'], next);
|
||||
},
|
||||
@@ -42,9 +40,7 @@ module.exports = function (Posts) {
|
||||
}
|
||||
});
|
||||
|
||||
var cids = postData.map(function (post) {
|
||||
return map[post.tid];
|
||||
});
|
||||
var cids = postData.map(post => map[post.tid]);
|
||||
next(null, cids);
|
||||
},
|
||||
], callback);
|
||||
|
||||
@@ -64,10 +64,10 @@ module.exports = function (privileges) {
|
||||
var isAdminOrMod = results.isAdministrator || results.isModerator;
|
||||
|
||||
plugins.fireHook('filter:privileges.categories.get', {
|
||||
'topics:create': privData['topics:create'] || isAdminOrMod,
|
||||
'topics:read': privData['topics:read'] || isAdminOrMod,
|
||||
'topics:tag': privData['topics:tag'] || isAdminOrMod,
|
||||
read: privData.read || isAdminOrMod,
|
||||
'topics:create': privData['topics:create'] || results.isAdministrator,
|
||||
'topics:read': privData['topics:read'] || results.isAdministrator,
|
||||
'topics:tag': privData['topics:tag'] || results.isAdministrator,
|
||||
read: privData.read || results.isAdministrator,
|
||||
cid: cid,
|
||||
uid: uid,
|
||||
editable: isAdminOrMod,
|
||||
@@ -94,7 +94,7 @@ module.exports = function (privileges) {
|
||||
|
||||
privileges.categories.isUserAllowedTo = function (privilege, cid, uid, callback) {
|
||||
if (!cid) {
|
||||
return callback(null, false);
|
||||
return setImmediate(callback, null, false);
|
||||
}
|
||||
if (Array.isArray(cid)) {
|
||||
helpers.isUserAllowedTo(privilege, uid, cid, function (err, results) {
|
||||
@@ -109,30 +109,18 @@ module.exports = function (privileges) {
|
||||
|
||||
privileges.categories.can = function (privilege, cid, uid, callback) {
|
||||
if (!cid) {
|
||||
return callback(null, false);
|
||||
return setImmediate(callback, null, false);
|
||||
}
|
||||
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
categories.getCategoryField(cid, 'disabled', next);
|
||||
async.parallel({
|
||||
disabled: async.apply(categories.getCategoryField, cid, 'disabled'),
|
||||
isAdmin: async.apply(user.isAdministrator, uid),
|
||||
isAllowed: async.apply(privileges.categories.isUserAllowedTo, privilege, cid, uid),
|
||||
}, next);
|
||||
},
|
||||
function (disabled, next) {
|
||||
if (disabled) {
|
||||
return callback(null, false);
|
||||
}
|
||||
helpers.some([
|
||||
function (next) {
|
||||
helpers.isUserAllowedTo(privilege, uid, [cid], function (err, results) {
|
||||
next(err, Array.isArray(results) && results.length ? results[0] : false);
|
||||
});
|
||||
},
|
||||
function (next) {
|
||||
user.isModerator(uid, cid, next);
|
||||
},
|
||||
function (next) {
|
||||
user.isAdministrator(uid, next);
|
||||
},
|
||||
], next);
|
||||
function (results, next) {
|
||||
next(null, !results.disabled && (results.isAllowed || results.isAdmin));
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
@@ -151,7 +139,7 @@ module.exports = function (privileges) {
|
||||
function (results, next) {
|
||||
cids = cids.filter(function (cid, index) {
|
||||
return !results.categories[index].disabled &&
|
||||
(results.allowedTo[index] || results.isAdmin || results.isModerators[index]);
|
||||
(results.allowedTo[index] || results.isAdmin);
|
||||
});
|
||||
|
||||
next(null, cids.filter(Boolean));
|
||||
@@ -167,9 +155,6 @@ module.exports = function (privileges) {
|
||||
allowedTo: function (next) {
|
||||
helpers.isUserAllowedTo(privilege, uid, cids, next);
|
||||
},
|
||||
isModerators: function (next) {
|
||||
user.isModerator(uid, cids, next);
|
||||
},
|
||||
isAdmin: function (next) {
|
||||
user.isAdministrator(uid, next);
|
||||
},
|
||||
@@ -178,7 +163,7 @@ module.exports = function (privileges) {
|
||||
|
||||
privileges.categories.filterUids = function (privilege, cid, uids, callback) {
|
||||
if (!uids.length) {
|
||||
return callback(null, []);
|
||||
return setImmediate(callback, null, []);
|
||||
}
|
||||
|
||||
uids = _.uniq(uids);
|
||||
@@ -189,9 +174,6 @@ module.exports = function (privileges) {
|
||||
allowedTo: function (next) {
|
||||
helpers.isUsersAllowedTo(privilege, uids, cid, next);
|
||||
},
|
||||
isModerators: function (next) {
|
||||
user.isModerator(uids, cid, next);
|
||||
},
|
||||
isAdmins: function (next) {
|
||||
user.isAdministrator(uids, next);
|
||||
},
|
||||
@@ -199,7 +181,7 @@ module.exports = function (privileges) {
|
||||
},
|
||||
function (results, next) {
|
||||
uids = uids.filter(function (uid, index) {
|
||||
return results.allowedTo[index] || results.isModerators[index] || results.isAdmins[index];
|
||||
return results.allowedTo[index] || results.isAdmins[index];
|
||||
});
|
||||
next(null, uids);
|
||||
},
|
||||
@@ -218,19 +200,12 @@ module.exports = function (privileges) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
async.parallel({
|
||||
isAdministrator: function (next) {
|
||||
user.isAdministrator(uid, next);
|
||||
},
|
||||
moderatorOfCurrent: function (next) {
|
||||
user.isModerator(uid, currentCid, next);
|
||||
},
|
||||
moderatorOfTarget: function (next) {
|
||||
user.isModerator(uid, targetCid, next);
|
||||
},
|
||||
isAdmin: async.apply(user.isAdministrator, uid),
|
||||
isModerators: async.apply(user.isModerator, uid, [currentCid, targetCid]),
|
||||
}, next);
|
||||
},
|
||||
function (results, next) {
|
||||
next(null, results.isAdministrator || (results.moderatorOfCurrent && results.moderatorOfTarget));
|
||||
next(null, results.isAdmin || !results.isModerators.includes(false));
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
|
||||
@@ -84,25 +84,21 @@ module.exports = function (privileges) {
|
||||
isAdministrator: function (next) {
|
||||
user.isAdministrator(uid, next);
|
||||
},
|
||||
isGlobalModerator: function (next) {
|
||||
user.isGlobalModerator(uid, next);
|
||||
},
|
||||
}, next);
|
||||
},
|
||||
function (results, next) {
|
||||
var privData = _.zipObject(privileges.global.userPrivilegeList, results.privileges);
|
||||
var isAdminOrMod = results.isAdministrator || results.isGlobalModerator;
|
||||
|
||||
plugins.fireHook('filter:privileges.global.get', {
|
||||
chat: privData.chat || isAdminOrMod,
|
||||
'upload:post:image': privData['upload:post:image'] || isAdminOrMod,
|
||||
'upload:post:file': privData['upload:post:file'] || isAdminOrMod,
|
||||
'search:content': privData['search:content'] || isAdminOrMod,
|
||||
'search:users': privData['search:users'] || isAdminOrMod,
|
||||
'search:tags': privData['search:tags'] || isAdminOrMod,
|
||||
'view:users': privData['view:users'] || isAdminOrMod,
|
||||
'view:tags': privData['view:tags'] || isAdminOrMod,
|
||||
'view:groups': privData['view:groups'] || isAdminOrMod,
|
||||
chat: privData.chat || results.isAdministrator,
|
||||
'upload:post:image': privData['upload:post:image'] || results.isAdministrator,
|
||||
'upload:post:file': privData['upload:post:file'] || results.isAdministrator,
|
||||
'search:content': privData['search:content'] || results.isAdministrator,
|
||||
'search:users': privData['search:users'] || results.isAdministrator,
|
||||
'search:tags': privData['search:tags'] || results.isAdministrator,
|
||||
'view:users': privData['view:users'] || results.isAdministrator,
|
||||
'view:tags': privData['view:tags'] || results.isAdministrator,
|
||||
'view:groups': privData['view:groups'] || results.isAdministrator,
|
||||
}, next);
|
||||
},
|
||||
], callback);
|
||||
@@ -115,9 +111,6 @@ module.exports = function (privileges) {
|
||||
next(err, Array.isArray(results) && results.length ? results[0] : false);
|
||||
});
|
||||
},
|
||||
function (next) {
|
||||
user.isGlobalModerator(uid, next);
|
||||
},
|
||||
function (next) {
|
||||
user.isAdministrator(uid, next);
|
||||
},
|
||||
|
||||
@@ -106,18 +106,12 @@ helpers.isUsersAllowedTo = function (privilege, uids, cid, callback) {
|
||||
};
|
||||
|
||||
function isSystemGroupAllowedToCids(privilege, uid, cids, callback) {
|
||||
var groupKeys = cids.map(function (cid) {
|
||||
return 'cid:' + cid + ':privileges:groups:' + privilege;
|
||||
});
|
||||
|
||||
const groupKeys = cids.map(cid => 'cid:' + cid + ':privileges:groups:' + privilege);
|
||||
groups.isMemberOfGroups(uidToSystemGroup[uid], groupKeys, callback);
|
||||
}
|
||||
|
||||
function isSystemGroupAllowedToPrivileges(privileges, uid, cid, callback) {
|
||||
var groupKeys = privileges.map(function (privilege) {
|
||||
return 'cid:' + cid + ':privileges:groups:' + privilege;
|
||||
});
|
||||
|
||||
const groupKeys = privileges.map(privilege => 'cid:' + cid + ':privileges:groups:' + privilege);
|
||||
groups.isMemberOfGroups(uidToSystemGroup[uid], groupKeys, callback);
|
||||
}
|
||||
|
||||
@@ -128,15 +122,11 @@ helpers.getUserPrivileges = function (cid, hookName, userPrivilegeList, callback
|
||||
async.apply(plugins.fireHook, hookName, userPrivilegeList.slice()),
|
||||
function (_privs, next) {
|
||||
userPrivileges = _privs;
|
||||
groups.getMembersOfGroups(userPrivileges.map(function (privilege) {
|
||||
return 'cid:' + cid + ':privileges:' + privilege;
|
||||
}), next);
|
||||
groups.getMembersOfGroups(userPrivileges.map(privilege => 'cid:' + cid + ':privileges:' + privilege), next);
|
||||
},
|
||||
function (_memberSets, next) {
|
||||
memberSets = _memberSets.map(function (set) {
|
||||
return set.map(function (uid) {
|
||||
return parseInt(uid, 10);
|
||||
});
|
||||
return set.map(uid => parseInt(uid, 10));
|
||||
});
|
||||
|
||||
var members = _.uniq(_.flatten(memberSets));
|
||||
@@ -164,9 +154,7 @@ helpers.getGroupPrivileges = function (cid, hookName, groupPrivilegeList, callba
|
||||
groupPrivileges = _privs;
|
||||
async.parallel({
|
||||
memberSets: function (next) {
|
||||
groups.getMembersOfGroups(groupPrivileges.map(function (privilege) {
|
||||
return 'cid:' + cid + ':privileges:' + privilege;
|
||||
}), next);
|
||||
groups.getMembersOfGroups(groupPrivileges.map(privilege => 'cid:' + cid + ':privileges:' + privilege), next);
|
||||
},
|
||||
groupNames: function (next) {
|
||||
groups.getGroups('groups:createtime', 0, -1, next);
|
||||
@@ -177,17 +165,11 @@ helpers.getGroupPrivileges = function (cid, hookName, groupPrivilegeList, callba
|
||||
var memberSets = results.memberSets;
|
||||
var uniqueGroups = _.uniq(_.flatten(memberSets));
|
||||
|
||||
var groupNames = results.groupNames.filter(function (groupName) {
|
||||
return !groupName.includes(':privileges:') && uniqueGroups.includes(groupName);
|
||||
});
|
||||
var groupNames = results.groupNames.filter(groupName => !groupName.includes(':privileges:') && uniqueGroups.includes(groupName));
|
||||
|
||||
groupNames = groups.ephemeralGroups.concat(groupNames);
|
||||
var registeredUsersIndex = groupNames.indexOf('registered-users');
|
||||
if (registeredUsersIndex !== -1) {
|
||||
groupNames.splice(0, 0, groupNames.splice(registeredUsersIndex, 1)[0]);
|
||||
} else {
|
||||
groupNames = ['registered-users'].concat(groupNames);
|
||||
}
|
||||
moveToFront(groupNames, 'Global Moderators');
|
||||
moveToFront(groupNames, 'registered-users');
|
||||
|
||||
var adminIndex = groupNames.indexOf('administrators');
|
||||
if (adminIndex !== -1) {
|
||||
@@ -227,6 +209,15 @@ helpers.getGroupPrivileges = function (cid, hookName, groupPrivilegeList, callba
|
||||
], callback);
|
||||
};
|
||||
|
||||
function moveToFront(groupNames, groupToMove) {
|
||||
const index = groupNames.indexOf(groupToMove);
|
||||
if (index !== -1) {
|
||||
groupNames.splice(0, 0, groupNames.splice(index, 1)[0]);
|
||||
} else {
|
||||
groupNames.unshift(groupToMove);
|
||||
}
|
||||
}
|
||||
|
||||
helpers.giveOrRescind = function (method, privileges, cids, groupNames, callback) {
|
||||
groupNames = Array.isArray(groupNames) ? groupNames : [groupNames];
|
||||
cids = Array.isArray(cids) ? cids : [cids];
|
||||
|
||||
@@ -16,39 +16,49 @@ module.exports = function (privileges) {
|
||||
|
||||
privileges.posts.get = function (pids, uid, callback) {
|
||||
if (!Array.isArray(pids) || !pids.length) {
|
||||
return callback(null, []);
|
||||
return setImmediate(callback, null, []);
|
||||
}
|
||||
|
||||
let uniqueCids;
|
||||
let cids;
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
posts.getCidsByPids(pids, next);
|
||||
},
|
||||
function (cids, next) {
|
||||
function (_cids, next) {
|
||||
cids = _cids;
|
||||
uniqueCids = _.uniq(cids);
|
||||
async.parallel({
|
||||
isAdmin: async.apply(user.isAdministrator, uid),
|
||||
isModerator: async.apply(user.isModerator, uid, cids),
|
||||
isModerator: async.apply(user.isModerator, uid, uniqueCids),
|
||||
isOwner: async.apply(posts.isOwner, pids, uid),
|
||||
'topics:read': async.apply(helpers.isUserAllowedTo, 'topics:read', uid, cids),
|
||||
read: async.apply(helpers.isUserAllowedTo, 'read', uid, cids),
|
||||
'posts:edit': async.apply(helpers.isUserAllowedTo, 'posts:edit', uid, cids),
|
||||
'posts:history': async.apply(helpers.isUserAllowedTo, 'posts:history', uid, cids),
|
||||
'posts:view_deleted': async.apply(helpers.isUserAllowedTo, 'posts:view_deleted', uid, cids),
|
||||
'topics:read': async.apply(helpers.isUserAllowedTo, 'topics:read', uid, uniqueCids),
|
||||
read: async.apply(helpers.isUserAllowedTo, 'read', uid, uniqueCids),
|
||||
'posts:edit': async.apply(helpers.isUserAllowedTo, 'posts:edit', uid, uniqueCids),
|
||||
'posts:history': async.apply(helpers.isUserAllowedTo, 'posts:history', uid, uniqueCids),
|
||||
'posts:view_deleted': async.apply(helpers.isUserAllowedTo, 'posts:view_deleted', uid, uniqueCids),
|
||||
}, next);
|
||||
},
|
||||
function (results, next) {
|
||||
var privileges = pids.map(function (pid, i) {
|
||||
var isAdminOrMod = results.isAdmin || results.isModerator[i];
|
||||
var editable = isAdminOrMod || (results.isOwner[i] && results['posts:edit'][i]);
|
||||
var viewDeletedPosts = isAdminOrMod || results.isOwner[i] || results['posts:view_deleted'][i];
|
||||
var viewHistory = isAdminOrMod || results.isOwner[i] || results['posts:history'][i];
|
||||
const isModerator = _.zipObject(uniqueCids, results.isModerator);
|
||||
const privData = {};
|
||||
privData['topics:read'] = _.zipObject(uniqueCids, results['topics:read']);
|
||||
privData.read = _.zipObject(uniqueCids, results.read);
|
||||
privData['posts:edit'] = _.zipObject(uniqueCids, results['posts:edit']);
|
||||
privData['posts:history'] = _.zipObject(uniqueCids, results['posts:history']);
|
||||
privData['posts:view_deleted'] = _.zipObject(uniqueCids, results['posts:view_deleted']);
|
||||
|
||||
var privileges = cids.map(function (cid, i) {
|
||||
var isAdminOrMod = results.isAdmin || isModerator[cid];
|
||||
var editable = (privData['posts:edit'][cid] && (results.isOwner[i] || results.isModerator)) || results.isAdmin;
|
||||
var viewDeletedPosts = results.isOwner[i] || privData['posts:view_deleted'][cid] || results.isAdmin;
|
||||
var viewHistory = results.isOwner[i] || privData['posts:history'][cid] || results.isAdmin;
|
||||
|
||||
return {
|
||||
editable: editable,
|
||||
view_deleted: editable,
|
||||
move: isAdminOrMod,
|
||||
isAdminOrMod: isAdminOrMod,
|
||||
'topics:read': results['topics:read'][i] || isAdminOrMod,
|
||||
read: results.read[i] || isAdminOrMod,
|
||||
'topics:read': privData['topics:read'][cid] || results.isAdmin,
|
||||
read: privData.read[cid] || results.isAdmin,
|
||||
'posts:history': viewHistory,
|
||||
'posts:view_deleted': viewDeletedPosts,
|
||||
};
|
||||
@@ -72,7 +82,7 @@ module.exports = function (privileges) {
|
||||
|
||||
privileges.posts.filter = function (privilege, pids, uid, callback) {
|
||||
if (!Array.isArray(pids) || !pids.length) {
|
||||
return callback(null, []);
|
||||
return setImmediate(callback, null, []);
|
||||
}
|
||||
var cids;
|
||||
var postData;
|
||||
@@ -112,18 +122,16 @@ module.exports = function (privileges) {
|
||||
privileges.categories.getBase(privilege, cids, uid, next);
|
||||
},
|
||||
function (results, next) {
|
||||
var isModOf = {};
|
||||
cids = cids.filter(function (cid, index) {
|
||||
isModOf[cid] = results.isModerators[index];
|
||||
return !results.categories[index].disabled &&
|
||||
(results.allowedTo[index] || results.isAdmin || results.isModerators[index]);
|
||||
(results.allowedTo[index] || results.isAdmin);
|
||||
});
|
||||
|
||||
const cidsSet = new Set(cids);
|
||||
|
||||
pids = postData.filter(function (post) {
|
||||
return post.topic && cidsSet.has(post.topic.cid) &&
|
||||
((!post.topic.deleted && !post.deleted) || results.isAdmin || isModOf[post.cid]);
|
||||
((!post.topic.deleted && !post.deleted) || results.isAdmin);
|
||||
}).map(post => post.pid);
|
||||
|
||||
plugins.fireHook('filter:privileges.posts.filter', {
|
||||
@@ -138,19 +146,41 @@ module.exports = function (privileges) {
|
||||
};
|
||||
|
||||
privileges.posts.canEdit = function (pid, uid, callback) {
|
||||
let results;
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
async.parallel({
|
||||
isEditable: async.apply(isPostEditable, pid, uid),
|
||||
isAdminOrMod: async.apply(isAdminOrMod, pid, uid),
|
||||
isAdmin: async.apply(privileges.users.isAdministrator, uid),
|
||||
isMod: async.apply(posts.isModerator, [pid], uid),
|
||||
owner: async.apply(posts.isOwner, pid, uid),
|
||||
edit: async.apply(privileges.posts.can, 'posts:edit', pid, uid),
|
||||
postData: async.apply(posts.getPostFields, pid, ['tid', 'timestamp']),
|
||||
}, next);
|
||||
},
|
||||
function (results, next) {
|
||||
if (results.isAdminOrMod) {
|
||||
return next(null, { flag: true });
|
||||
function (_results, next) {
|
||||
results = _results;
|
||||
results.isMod = results.isMod[0];
|
||||
if (results.isAdmin) {
|
||||
return callback(null, { flag: true });
|
||||
}
|
||||
|
||||
next(null, results.isEditable);
|
||||
if (!results.isMod && meta.config.postEditDuration && (Date.now() - results.postData.timestamp > meta.config.postEditDuration * 1000)) {
|
||||
return callback(null, { flag: false, message: '[[error:post-edit-duration-expired, ' + meta.config.postEditDuration + ']]' });
|
||||
}
|
||||
topics.isLocked(results.postData.tid, next);
|
||||
},
|
||||
function (isLocked, next) {
|
||||
if (!results.isMod && isLocked) {
|
||||
return callback(null, { flag: false, message: '[[error:topic-locked]]' });
|
||||
}
|
||||
|
||||
results.pid = parseInt(pid, 10);
|
||||
results.uid = uid;
|
||||
|
||||
plugins.fireHook('filter:privileges.posts.edit', results, next);
|
||||
},
|
||||
function (result, next) {
|
||||
next(null, { flag: result.edit && (result.owner || result.isMod), message: '[[error:no-privileges]]' });
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
@@ -164,31 +194,29 @@ module.exports = function (privileges) {
|
||||
function (_postData, next) {
|
||||
postData = _postData;
|
||||
async.parallel({
|
||||
isAdminOrMod: async.apply(isAdminOrMod, pid, uid),
|
||||
isAdmin: async.apply(privileges.users.isAdministrator, uid),
|
||||
isMod: async.apply(posts.isModerator, [pid], uid),
|
||||
isLocked: async.apply(topics.isLocked, postData.tid),
|
||||
isOwner: async.apply(posts.isOwner, pid, uid),
|
||||
'posts:delete': async.apply(privileges.posts.can, 'posts:delete', pid, uid),
|
||||
}, next);
|
||||
},
|
||||
function (results, next) {
|
||||
if (results.isAdminOrMod) {
|
||||
results.isMod = results.isMod[0];
|
||||
if (results.isAdmin) {
|
||||
return next(null, { flag: true });
|
||||
}
|
||||
|
||||
if (results.isLocked) {
|
||||
if (!results.isMod && results.isLocked) {
|
||||
return next(null, { flag: false, message: '[[error:topic-locked]]' });
|
||||
}
|
||||
|
||||
if (!results['posts:delete']) {
|
||||
return next(null, { flag: false, message: '[[error:no-privileges]]' });
|
||||
}
|
||||
|
||||
var postDeleteDuration = meta.config.postDeleteDuration;
|
||||
if (postDeleteDuration && (Date.now() - postData.timestamp > postDeleteDuration * 1000)) {
|
||||
if (!results.isMod && postDeleteDuration && (Date.now() - postData.timestamp > postDeleteDuration * 1000)) {
|
||||
return next(null, { flag: false, message: '[[error:post-delete-duration-expired, ' + meta.config.postDeleteDuration + ']]' });
|
||||
}
|
||||
var deleterUid = postData.deleterUid;
|
||||
var flag = results.isOwner && (deleterUid === 0 || deleterUid === postData.uid);
|
||||
var flag = results['posts:delete'] && ((results.isOwner && (deleterUid === 0 || deleterUid === postData.uid)) || results.isMod);
|
||||
next(null, { flag: flag, message: '[[error:no-privileges]]' });
|
||||
},
|
||||
], callback);
|
||||
@@ -233,51 +261,16 @@ module.exports = function (privileges) {
|
||||
async.parallel({
|
||||
purge: async.apply(privileges.categories.isUserAllowedTo, 'purge', cid, uid),
|
||||
owner: async.apply(posts.isOwner, pid, uid),
|
||||
isAdminOrMod: async.apply(privileges.categories.isAdminOrMod, cid, uid),
|
||||
isAdmin: async.apply(privileges.users.isAdministrator, uid),
|
||||
isModerator: async.apply(privileges.users.isModerator, uid, cid),
|
||||
}, next);
|
||||
},
|
||||
function (results, next) {
|
||||
next(null, results.isAdminOrMod || (results.purge && results.owner));
|
||||
next(null, (results.purge && (results.owner || results.isModerator)) || results.isAdmin);
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
|
||||
function isPostEditable(pid, uid, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
posts.getPostFields(pid, ['tid', 'timestamp'], next);
|
||||
},
|
||||
function (postData, next) {
|
||||
var postEditDuration = meta.config.postEditDuration;
|
||||
if (postEditDuration && (Date.now() - postData.timestamp > postEditDuration * 1000)) {
|
||||
return callback(null, { flag: false, message: '[[error:post-edit-duration-expired, ' + meta.config.postEditDuration + ']]' });
|
||||
}
|
||||
topics.isLocked(postData.tid, next);
|
||||
},
|
||||
function (isLocked, next) {
|
||||
if (isLocked) {
|
||||
return callback(null, { flag: false, message: '[[error:topic-locked]]' });
|
||||
}
|
||||
|
||||
async.parallel({
|
||||
owner: async.apply(posts.isOwner, pid, uid),
|
||||
edit: async.apply(privileges.posts.can, 'posts:edit', pid, uid),
|
||||
}, next);
|
||||
},
|
||||
(result, next) => {
|
||||
Object.assign(result, {
|
||||
pid: parseInt(pid, 10),
|
||||
uid: uid,
|
||||
});
|
||||
|
||||
plugins.fireHook('filter:privileges.posts.edit', result, next);
|
||||
},
|
||||
function (result, next) {
|
||||
next(null, { flag: result.owner && result.edit, message: '[[error:no-privileges]]' });
|
||||
},
|
||||
], callback);
|
||||
}
|
||||
|
||||
function isAdminOrMod(pid, uid, callback) {
|
||||
helpers.some([
|
||||
function (next) {
|
||||
|
||||
@@ -38,23 +38,23 @@ module.exports = function (privileges) {
|
||||
var isOwner = uid > 0 && uid === topic.uid;
|
||||
var isAdminOrMod = results.isAdministrator || results.isModerator;
|
||||
var editable = isAdminOrMod;
|
||||
var deletable = isAdminOrMod || (isOwner && privData['topics:delete']);
|
||||
var purge = results.isAdministrator || privData.purge;
|
||||
var deletable = (privData['topics:delete'] && (isOwner || results.isModerator)) || results.isAdministrator;
|
||||
|
||||
plugins.fireHook('filter:privileges.topics.get', {
|
||||
'topics:reply': (privData['topics:reply'] && !topic.locked && !topic.deleted) || isAdminOrMod,
|
||||
'topics:read': privData['topics:read'] || isAdminOrMod,
|
||||
'topics:tag': privData['topics:tag'] || isAdminOrMod,
|
||||
'topics:delete': (isOwner && privData['topics:delete']) || isAdminOrMod,
|
||||
'posts:edit': (privData['posts:edit'] && !topic.locked) || isAdminOrMod,
|
||||
'posts:history': privData['posts:history'] || isAdminOrMod,
|
||||
'posts:delete': (privData['posts:delete'] && !topic.locked) || isAdminOrMod,
|
||||
'posts:view_deleted': privData['posts:view_deleted'] || isAdminOrMod,
|
||||
read: privData.read || isAdminOrMod,
|
||||
'topics:reply': (privData['topics:reply'] && ((!topic.locked && !topic.deleted) || results.isModerator)) || results.isAdministrator,
|
||||
'topics:read': privData['topics:read'] || results.isAdministrator,
|
||||
'topics:tag': privData['topics:tag'] || results.isAdministrator,
|
||||
'topics:delete': (privData['topics:delete'] && (isOwner || results.isModerator)) || results.isAdministrator,
|
||||
'posts:edit': (privData['posts:edit'] && (!topic.locked || results.isModerator)) || results.isAdministrator,
|
||||
'posts:history': privData['posts:history'] || results.isAdministrator,
|
||||
'posts:delete': (privData['posts:delete'] && (!topic.locked || results.isModerator)) || results.isAdministrator,
|
||||
'posts:view_deleted': privData['posts:view_deleted'] || results.isAdministrator,
|
||||
read: privData.read || results.isAdministrator,
|
||||
purge: (privData.purge && (isOwner || results.isModerator)) || results.isAdministrator,
|
||||
|
||||
view_thread_tools: editable || deletable,
|
||||
editable: editable,
|
||||
deletable: deletable,
|
||||
purge: purge,
|
||||
view_deleted: isAdminOrMod || isOwner,
|
||||
isAdminOrMod: isAdminOrMod,
|
||||
disabled: results.disabled,
|
||||
@@ -93,18 +93,16 @@ module.exports = function (privileges) {
|
||||
privileges.categories.getBase(privilege, cids, uid, next);
|
||||
},
|
||||
function (results, next) {
|
||||
var isModOf = {};
|
||||
cids = cids.filter(function (cid, index) {
|
||||
isModOf[cid] = results.isModerators[index];
|
||||
return !results.categories[index].disabled &&
|
||||
(results.allowedTo[index] || results.isAdmin || results.isModerators[index]);
|
||||
(results.allowedTo[index] || results.isAdmin);
|
||||
});
|
||||
|
||||
const cidsSet = new Set(cids);
|
||||
|
||||
tids = topicsData.filter(function (topic) {
|
||||
return cidsSet.has(topic.cid) &&
|
||||
(!topic.deleted || results.isAdmin || isModOf[topic.cid]);
|
||||
(!topic.deleted || results.isAdmin);
|
||||
}).map(topic => topic.tid);
|
||||
|
||||
plugins.fireHook('filter:privileges.topics.filter', {
|
||||
@@ -120,7 +118,7 @@ module.exports = function (privileges) {
|
||||
|
||||
privileges.topics.filterUids = function (privilege, tid, uids, callback) {
|
||||
if (!Array.isArray(uids) || !uids.length) {
|
||||
return callback(null, []);
|
||||
return setImmediate(callback, null, []);
|
||||
}
|
||||
|
||||
uids = _.uniq(uids);
|
||||
@@ -138,9 +136,6 @@ module.exports = function (privileges) {
|
||||
allowedTo: function (next) {
|
||||
helpers.isUsersAllowedTo(privilege, uids, topicData.cid, next);
|
||||
},
|
||||
isModerators: function (next) {
|
||||
user.isModerator(uids, topicData.cid, next);
|
||||
},
|
||||
isAdmins: function (next) {
|
||||
user.isAdministrator(uids, next);
|
||||
},
|
||||
@@ -149,7 +144,7 @@ module.exports = function (privileges) {
|
||||
function (results, next) {
|
||||
uids = uids.filter(function (uid, index) {
|
||||
return !results.disabled &&
|
||||
((results.allowedTo[index] && !topicData.deleted) || results.isAdmins[index] || results.isModerators[index]);
|
||||
((results.allowedTo[index] && !topicData.deleted) || results.isAdmins[index]);
|
||||
});
|
||||
|
||||
next(null, uids);
|
||||
@@ -166,11 +161,12 @@ module.exports = function (privileges) {
|
||||
async.parallel({
|
||||
purge: async.apply(privileges.categories.isUserAllowedTo, 'purge', cid, uid),
|
||||
owner: async.apply(topics.isOwner, tid, uid),
|
||||
isAdminOrMod: async.apply(privileges.categories.isAdminOrMod, cid, uid),
|
||||
isAdmin: async.apply(privileges.users.isAdministrator, uid),
|
||||
isModerator: async.apply(privileges.users.isModerator, uid, cid),
|
||||
}, next);
|
||||
},
|
||||
function (results, next) {
|
||||
next(null, results.isAdminOrMod || (results.purge && results.owner));
|
||||
next(null, (results.purge && (results.owner || results.isModerator)) || results.isAdmin);
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
@@ -191,23 +187,19 @@ module.exports = function (privileges) {
|
||||
}, next);
|
||||
},
|
||||
function (results, next) {
|
||||
if (results.isModerator || results.isAdministrator) {
|
||||
if (results.isAdministrator) {
|
||||
return next(null, true);
|
||||
}
|
||||
|
||||
var preventTopicDeleteAfterReplies = meta.config.preventTopicDeleteAfterReplies;
|
||||
if (preventTopicDeleteAfterReplies && (topicData.postcount - 1) >= preventTopicDeleteAfterReplies) {
|
||||
if (!results.isModerator && preventTopicDeleteAfterReplies && (topicData.postcount - 1) >= preventTopicDeleteAfterReplies) {
|
||||
var langKey = preventTopicDeleteAfterReplies > 1 ?
|
||||
'[[error:cant-delete-topic-has-replies, ' + meta.config.preventTopicDeleteAfterReplies + ']]' :
|
||||
'[[error:cant-delete-topic-has-reply]]';
|
||||
return next(new Error(langKey));
|
||||
}
|
||||
|
||||
if (!results['topics:delete'][0]) {
|
||||
return next(null, false);
|
||||
}
|
||||
|
||||
next(null, results.isOwner);
|
||||
next(null, results['topics:delete'][0] && (results.isOwner || results.isModerator));
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
|
||||
@@ -48,7 +48,7 @@ module.exports = function (privileges) {
|
||||
},
|
||||
function (isGlobalModerator, next) {
|
||||
if (isGlobalModerator) {
|
||||
return filterIsModerator(cids, uid, cids.map(function () { return true; }), callback);
|
||||
return filterIsModerator(cids, uid, cids.map(() => true), callback);
|
||||
}
|
||||
|
||||
uniqueCids = _.uniq(cids);
|
||||
@@ -56,16 +56,8 @@ module.exports = function (privileges) {
|
||||
helpers.isUserAllowedTo('moderate', uid, uniqueCids, next);
|
||||
},
|
||||
function (isAllowed, next) {
|
||||
var map = {};
|
||||
|
||||
uniqueCids.forEach(function (cid, index) {
|
||||
map[cid] = isAllowed[index];
|
||||
});
|
||||
|
||||
var isModerator = cids.map(function (cid) {
|
||||
return map[cid];
|
||||
});
|
||||
|
||||
const map = _.zipObject(uniqueCids, isAllowed);
|
||||
const isModerator = cids.map(cid => map[cid]);
|
||||
filterIsModerator(cids, uid, isModerator, next);
|
||||
},
|
||||
], callback);
|
||||
|
||||
88
src/upgrades/1.12.3/give_mod_privileges.js
Normal file
88
src/upgrades/1.12.3/give_mod_privileges.js
Normal file
@@ -0,0 +1,88 @@
|
||||
'use strict';
|
||||
|
||||
var async = require('async');
|
||||
var privileges = require('../../privileges');
|
||||
var groups = require('../../groups');
|
||||
var db = require('../../database');
|
||||
|
||||
module.exports = {
|
||||
name: 'Give mods explicit privileges',
|
||||
timestamp: Date.UTC(2019, 4, 28),
|
||||
method: function (callback) {
|
||||
var defaultPrivileges = [
|
||||
'find',
|
||||
'read',
|
||||
'topics:read',
|
||||
'topics:create',
|
||||
'topics:reply',
|
||||
'topics:tag',
|
||||
'posts:edit',
|
||||
'posts:history',
|
||||
'posts:delete',
|
||||
'posts:upvote',
|
||||
'posts:downvote',
|
||||
'topics:delete',
|
||||
];
|
||||
const modPrivileges = defaultPrivileges.concat([
|
||||
'posts:view_deleted',
|
||||
'purge',
|
||||
'moderate',
|
||||
]);
|
||||
|
||||
const globalModPrivs = [
|
||||
'chat',
|
||||
'upload:post:image',
|
||||
'upload:post:file',
|
||||
'signature',
|
||||
'ban',
|
||||
'search:content',
|
||||
'search:users',
|
||||
'search:tags',
|
||||
'view:users',
|
||||
'view:tags',
|
||||
'view:groups',
|
||||
'local:login',
|
||||
];
|
||||
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
db.getSortedSetRevRange('categories:cid', 0, -1, next);
|
||||
},
|
||||
function (cids, next) {
|
||||
async.eachSeries(cids, function (cid, next) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
givePrivsToModerators(cid, '', next);
|
||||
},
|
||||
function (next) {
|
||||
givePrivsToModerators(cid, 'groups:', next);
|
||||
},
|
||||
function (next) {
|
||||
privileges.categories.give(modPrivileges, cid, ['Global Moderators'], next);
|
||||
},
|
||||
], next);
|
||||
}, next);
|
||||
},
|
||||
function (next) {
|
||||
privileges.global.give(globalModPrivs, 'Global Moderators', next);
|
||||
},
|
||||
], callback);
|
||||
|
||||
function givePrivsToModerators(cid, groupPrefix, callback) {
|
||||
const privGroups = modPrivileges.map(function (priv) {
|
||||
return 'cid:' + cid + ':privileges:' + groupPrefix + priv;
|
||||
});
|
||||
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
db.getSortedSetRevRange('group:cid:' + cid + ':privileges:' + groupPrefix + 'moderate:members', 0, -1, next);
|
||||
},
|
||||
function (members, next) {
|
||||
async.eachSeries(members, function (member, next) {
|
||||
groups.join(privGroups, member, next);
|
||||
}, next);
|
||||
},
|
||||
], callback);
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -850,8 +850,8 @@ describe('Categories', function () {
|
||||
Categories.getModeratorUids([1, 2], function (err, uids) {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(2, uids.length);
|
||||
assert.strictEqual(1, parseInt(uids[0], 10));
|
||||
assert.strictEqual(0, uids[1].length);
|
||||
assert(uids[0].includes('1'));
|
||||
assert.strictEqual(1, uids[1].length);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -265,6 +265,32 @@ describe('Post\'s', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('should not see post content if global mod does not have posts:view_deleted privilege', function (done) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
user.create({ username: 'global mod', password: '123456' }, next);
|
||||
},
|
||||
function (uid, next) {
|
||||
groups.join('Global Moderators', uid, next);
|
||||
},
|
||||
function (next) {
|
||||
privileges.categories.rescind(['posts:view_deleted'], cid, 'Global Moderators', next);
|
||||
},
|
||||
function (next) {
|
||||
helpers.loginUser('global mod', '123456', function (err, _jar) {
|
||||
assert.ifError(err);
|
||||
var jar = _jar;
|
||||
|
||||
request(nconf.get('url') + '/api/topic/' + tid, { jar: jar, json: true }, function (err, res, body) {
|
||||
assert.ifError(err);
|
||||
assert.equal(body.posts[1].content, '[[topic:post_is_deleted]]');
|
||||
privileges.categories.give(['posts:view_deleted'], cid, 'Global Moderators', next);
|
||||
});
|
||||
});
|
||||
},
|
||||
], done);
|
||||
});
|
||||
|
||||
it('should restore a post', function (done) {
|
||||
socketPosts.restore({ uid: voterUid }, { pid: replyPid, tid: tid }, function (err) {
|
||||
assert.ifError(err);
|
||||
|
||||
@@ -342,7 +342,7 @@ describe('Topic\'s', function () {
|
||||
});
|
||||
|
||||
it('should load topic tools', function (done) {
|
||||
socketTopics.loadTopicTools({ uid: 1 }, { tid: newTopic.tid }, function (err, data) {
|
||||
socketTopics.loadTopicTools({ uid: adminUid }, { tid: newTopic.tid }, function (err, data) {
|
||||
assert.ifError(err);
|
||||
assert(data);
|
||||
done();
|
||||
@@ -350,21 +350,21 @@ describe('Topic\'s', function () {
|
||||
});
|
||||
|
||||
it('should delete the topic', function (done) {
|
||||
socketTopics.delete({ uid: 1 }, { tids: [newTopic.tid], cid: categoryObj.cid }, function (err) {
|
||||
socketTopics.delete({ uid: adminUid }, { tids: [newTopic.tid], cid: categoryObj.cid }, function (err) {
|
||||
assert.ifError(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should restore the topic', function (done) {
|
||||
socketTopics.restore({ uid: 1 }, { tids: [newTopic.tid], cid: categoryObj.cid }, function (err) {
|
||||
socketTopics.restore({ uid: adminUid }, { tids: [newTopic.tid], cid: categoryObj.cid }, function (err) {
|
||||
assert.ifError(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should lock topic', function (done) {
|
||||
socketTopics.lock({ uid: 1 }, { tids: [newTopic.tid], cid: categoryObj.cid }, function (err) {
|
||||
socketTopics.lock({ uid: adminUid }, { tids: [newTopic.tid], cid: categoryObj.cid }, function (err) {
|
||||
assert.ifError(err);
|
||||
topics.isLocked(newTopic.tid, function (err, isLocked) {
|
||||
assert.ifError(err);
|
||||
@@ -375,7 +375,7 @@ describe('Topic\'s', function () {
|
||||
});
|
||||
|
||||
it('should unlock topic', function (done) {
|
||||
socketTopics.unlock({ uid: 1 }, { tids: [newTopic.tid], cid: categoryObj.cid }, function (err) {
|
||||
socketTopics.unlock({ uid: adminUid }, { tids: [newTopic.tid], cid: categoryObj.cid }, function (err) {
|
||||
assert.ifError(err);
|
||||
topics.isLocked(newTopic.tid, function (err, isLocked) {
|
||||
assert.ifError(err);
|
||||
@@ -386,7 +386,7 @@ describe('Topic\'s', function () {
|
||||
});
|
||||
|
||||
it('should pin topic', function (done) {
|
||||
socketTopics.pin({ uid: 1 }, { tids: [newTopic.tid], cid: categoryObj.cid }, function (err) {
|
||||
socketTopics.pin({ uid: adminUid }, { tids: [newTopic.tid], cid: categoryObj.cid }, function (err) {
|
||||
assert.ifError(err);
|
||||
topics.getTopicField(newTopic.tid, 'pinned', function (err, pinned) {
|
||||
assert.ifError(err);
|
||||
@@ -397,7 +397,7 @@ describe('Topic\'s', function () {
|
||||
});
|
||||
|
||||
it('should unpin topic', function (done) {
|
||||
socketTopics.unpin({ uid: 1 }, { tids: [newTopic.tid], cid: categoryObj.cid }, function (err) {
|
||||
socketTopics.unpin({ uid: adminUid }, { tids: [newTopic.tid], cid: categoryObj.cid }, function (err) {
|
||||
assert.ifError(err);
|
||||
topics.getTopicField(newTopic.tid, 'pinned', function (err, pinned) {
|
||||
assert.ifError(err);
|
||||
@@ -408,7 +408,7 @@ describe('Topic\'s', function () {
|
||||
});
|
||||
|
||||
it('should move all topics', function (done) {
|
||||
socketTopics.moveAll({ uid: 1 }, { cid: moveCid, currentCid: categoryObj.cid }, function (err) {
|
||||
socketTopics.moveAll({ uid: adminUid }, { cid: moveCid, currentCid: categoryObj.cid }, function (err) {
|
||||
assert.ifError(err);
|
||||
topics.getTopicField(newTopic.tid, 'cid', function (err, cid) {
|
||||
assert.ifError(err);
|
||||
@@ -419,7 +419,7 @@ describe('Topic\'s', function () {
|
||||
});
|
||||
|
||||
it('should move a topic', function (done) {
|
||||
socketTopics.move({ uid: 1 }, { cid: categoryObj.cid, tids: [newTopic.tid] }, function (err) {
|
||||
socketTopics.move({ uid: adminUid }, { cid: categoryObj.cid, tids: [newTopic.tid] }, function (err) {
|
||||
assert.ifError(err);
|
||||
topics.getTopicField(newTopic.tid, 'cid', function (err, cid) {
|
||||
assert.ifError(err);
|
||||
@@ -543,8 +543,40 @@ describe('Topic\'s', function () {
|
||||
], done);
|
||||
});
|
||||
|
||||
it('should fail to purge topic if user does not have privilege', function (done) {
|
||||
var globalModUid;
|
||||
var tid;
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
topics.post({
|
||||
uid: adminUid,
|
||||
title: 'topic for purge test',
|
||||
content: 'topic content',
|
||||
cid: categoryObj.cid,
|
||||
}, next);
|
||||
},
|
||||
function (result, next) {
|
||||
tid = result.topicData.tid;
|
||||
User.create({ username: 'global mod' }, next);
|
||||
},
|
||||
function (uid, next) {
|
||||
globalModUid = uid;
|
||||
groups.join('Global Moderators', uid, next);
|
||||
},
|
||||
function (next) {
|
||||
privileges.categories.rescind(['purge'], categoryObj.cid, 'Global Moderators', next);
|
||||
},
|
||||
function (next) {
|
||||
socketTopics.purge({ uid: globalModUid }, { tids: [tid], cid: categoryObj.cid }, function (err) {
|
||||
assert.equal(err.message, '[[error:no-privileges]]');
|
||||
privileges.categories.give(['purge'], categoryObj.cid, 'Global Moderators', next);
|
||||
});
|
||||
},
|
||||
], done);
|
||||
});
|
||||
|
||||
it('should purge the topic', function (done) {
|
||||
socketTopics.purge({ uid: 1 }, { tids: [newTopic.tid], cid: categoryObj.cid }, function (err) {
|
||||
socketTopics.purge({ uid: adminUid }, { tids: [newTopic.tid], cid: categoryObj.cid }, function (err) {
|
||||
assert.ifError(err);
|
||||
db.isSortedSetMember('uid:' + followerUid + ':followed_tids', newTopic.tid, function (err, isMember) {
|
||||
assert.ifError(err);
|
||||
@@ -588,7 +620,10 @@ describe('Topic\'s', function () {
|
||||
topics.tools.pin(tid1, adminUid, next);
|
||||
},
|
||||
function (next) {
|
||||
topics.tools.pin(tid2, adminUid, next);
|
||||
// artificial timeout so pin time is different on redis sometimes scores are indentical
|
||||
setTimeout(function () {
|
||||
topics.tools.pin(tid2, adminUid, next);
|
||||
}, 5);
|
||||
},
|
||||
], done);
|
||||
});
|
||||
@@ -822,7 +857,7 @@ describe('Topic\'s', function () {
|
||||
});
|
||||
|
||||
it('should fail with invalid data', function (done) {
|
||||
socketTopics.createTopicFromPosts({ uid: 1 }, null, function (err) {
|
||||
socketTopics.createTopicFromPosts({ uid: adminUid }, null, function (err) {
|
||||
assert.equal(err.message, '[[error:invalid-data]]');
|
||||
done();
|
||||
});
|
||||
@@ -939,8 +974,8 @@ describe('Topic\'s', function () {
|
||||
request(nconf.get('url') + '/api/topic/' + topicData.slug + '/-1', { json: true }, function (err, res, body) {
|
||||
assert.ifError(err);
|
||||
assert.equal(res.statusCode, 200);
|
||||
assert.equal(res.headers['x-redirect'], '/topic/15/topic-for-controller-test');
|
||||
assert.equal(body, '/topic/15/topic-for-controller-test');
|
||||
assert.equal(res.headers['x-redirect'], '/topic/' + topicData.tid + '/topic-for-controller-test');
|
||||
assert.equal(body, '/topic/' + topicData.tid + '/topic-for-controller-test');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user