mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-01-01 21:30:30 +01:00
feat: #7743 , user/block, user/categories
This commit is contained in:
@@ -16,117 +16,84 @@ module.exports = function (User) {
|
||||
}),
|
||||
};
|
||||
|
||||
User.blocks.is = function (targetUid, uid, callback) {
|
||||
User.blocks.list(uid, function (err, blocks) {
|
||||
callback(err, blocks.includes(parseInt(targetUid, 10)));
|
||||
});
|
||||
User.blocks.is = async function (targetUid, uid) {
|
||||
const blocks = await User.blocks.list(uid);
|
||||
return blocks.includes(parseInt(targetUid, 10));
|
||||
};
|
||||
|
||||
User.blocks.can = function (callerUid, blockerUid, blockeeUid, callback) {
|
||||
User.blocks.can = async function (callerUid, blockerUid, blockeeUid) {
|
||||
// Guests can't block
|
||||
if (blockerUid === 0 || blockeeUid === 0) {
|
||||
return setImmediate(callback, new Error('[[error:cannot-block-guest]]'));
|
||||
throw new Error('[[error:cannot-block-guest]]');
|
||||
} else if (blockerUid === blockeeUid) {
|
||||
return setImmediate(callback, new Error('[[error:cannot-block-self]]'));
|
||||
throw new Error('[[error:cannot-block-self]]');
|
||||
}
|
||||
|
||||
// Administrators and global moderators cannot be blocked
|
||||
// Only admins/mods can block users as another user
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
async.parallel({
|
||||
isCallerAdminOrMod: function (next) {
|
||||
User.isAdminOrGlobalMod(callerUid, next);
|
||||
},
|
||||
isBlockeeAdminOrMod: function (next) {
|
||||
User.isAdminOrGlobalMod(blockeeUid, next);
|
||||
},
|
||||
}, next);
|
||||
},
|
||||
function (results, next) {
|
||||
if (results.isBlockeeAdminOrMod) {
|
||||
return callback(new Error('[[error:cannot-block-privileged]]'));
|
||||
}
|
||||
if (parseInt(callerUid, 10) !== parseInt(blockerUid, 10) && !results.isCallerAdminOrMod) {
|
||||
return callback(new Error());
|
||||
}
|
||||
|
||||
next();
|
||||
},
|
||||
], callback);
|
||||
const [isCallerAdminOrMod, isBlockeeAdminOrMod] = await Promise.all([
|
||||
User.isAdminOrGlobalMod(callerUid),
|
||||
User.isAdminOrGlobalMod(blockeeUid),
|
||||
]);
|
||||
if (isBlockeeAdminOrMod) {
|
||||
throw new Error('[[error:cannot-block-privileged]]');
|
||||
}
|
||||
if (parseInt(callerUid, 10) !== parseInt(blockerUid, 10) && !isCallerAdminOrMod) {
|
||||
throw new Error();
|
||||
}
|
||||
};
|
||||
|
||||
User.blocks.list = function (uid, callback) {
|
||||
User.blocks.list = async function (uid) {
|
||||
if (User.blocks._cache.has(parseInt(uid, 10))) {
|
||||
return setImmediate(callback, null, User.blocks._cache.get(parseInt(uid, 10)));
|
||||
return User.blocks._cache.get(parseInt(uid, 10));
|
||||
}
|
||||
|
||||
db.getSortedSetRange('uid:' + uid + ':blocked_uids', 0, -1, function (err, blocked) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
blocked = blocked.map(uid => parseInt(uid, 10)).filter(Boolean);
|
||||
User.blocks._cache.set(parseInt(uid, 10), blocked);
|
||||
callback(null, blocked);
|
||||
});
|
||||
let blocked = await db.getSortedSetRange('uid:' + uid + ':blocked_uids', 0, -1);
|
||||
blocked = blocked.map(uid => parseInt(uid, 10)).filter(Boolean);
|
||||
User.blocks._cache.set(parseInt(uid, 10), blocked);
|
||||
return blocked;
|
||||
};
|
||||
|
||||
pubsub.on('user:blocks:cache:del', function (uid) {
|
||||
User.blocks._cache.del(uid);
|
||||
});
|
||||
|
||||
User.blocks.add = function (targetUid, uid, callback) {
|
||||
async.waterfall([
|
||||
async.apply(User.blocks.applyChecks, true, targetUid, uid),
|
||||
async.apply(db.sortedSetAdd.bind(db), 'uid:' + uid + ':blocked_uids', Date.now(), targetUid),
|
||||
async.apply(User.incrementUserFieldBy, uid, 'blocksCount', 1),
|
||||
function (_blank, next) {
|
||||
User.blocks._cache.del(parseInt(uid, 10));
|
||||
pubsub.publish('user:blocks:cache:del', parseInt(uid, 10));
|
||||
setImmediate(next);
|
||||
},
|
||||
], callback);
|
||||
User.blocks.add = async function (targetUid, uid) {
|
||||
await User.blocks.applyChecks('block', targetUid, uid);
|
||||
await db.sortedSetAdd('uid:' + uid + ':blocked_uids', Date.now(), targetUid);
|
||||
await User.incrementUserFieldBy(uid, 'blocksCount', 1);
|
||||
User.blocks._cache.del(parseInt(uid, 10));
|
||||
pubsub.publish('user:blocks:cache:del', parseInt(uid, 10));
|
||||
};
|
||||
|
||||
User.blocks.remove = function (targetUid, uid, callback) {
|
||||
async.waterfall([
|
||||
async.apply(User.blocks.applyChecks, false, targetUid, uid),
|
||||
async.apply(db.sortedSetRemove.bind(db), 'uid:' + uid + ':blocked_uids', targetUid),
|
||||
async.apply(User.decrementUserFieldBy, uid, 'blocksCount', 1),
|
||||
function (_blank, next) {
|
||||
User.blocks._cache.del(parseInt(uid, 10));
|
||||
pubsub.publish('user:blocks:cache:del', parseInt(uid, 10));
|
||||
setImmediate(next);
|
||||
},
|
||||
], callback);
|
||||
User.blocks.remove = async function (targetUid, uid) {
|
||||
await User.blocks.applyChecks('unblock', targetUid, uid);
|
||||
await db.sortedSetRemove('uid:' + uid + ':blocked_uids', targetUid);
|
||||
await User.decrementUserFieldBy(uid, 'blocksCount', 1);
|
||||
User.blocks._cache.del(parseInt(uid, 10));
|
||||
pubsub.publish('user:blocks:cache:del', parseInt(uid, 10));
|
||||
};
|
||||
|
||||
User.blocks.applyChecks = function (block, targetUid, uid, callback) {
|
||||
User.blocks.can(uid, uid, targetUid, function (err) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
User.blocks.applyChecks = async function (type, targetUid, uid) {
|
||||
await User.blocks.can(uid, uid, targetUid);
|
||||
const isBlock = type === 'block';
|
||||
const is = await User.blocks.is(targetUid, uid);
|
||||
if (is === isBlock) {
|
||||
throw new Error('[[error:already-' + (isBlock ? 'blocked' : 'unblocked') + ']]');
|
||||
}
|
||||
};
|
||||
|
||||
User.blocks.is(targetUid, uid, function (err, is) {
|
||||
callback(err || (is === block ? new Error('[[error:already-' + (block ? 'blocked' : 'unblocked') + ']]') : null));
|
||||
});
|
||||
User.blocks.filterUids = async function (targetUid, uids) {
|
||||
return await async.filter(uids, async function (uid) {
|
||||
const isBlocked = await User.blocks.is(targetUid, uid);
|
||||
return !isBlocked;
|
||||
});
|
||||
};
|
||||
|
||||
User.blocks.filterUids = function (targetUid, uids, callback) {
|
||||
async.filter(uids, function (uid, next) {
|
||||
User.blocks.is(targetUid, uid, function (err, blocked) {
|
||||
next(err, !blocked);
|
||||
});
|
||||
}, callback);
|
||||
};
|
||||
|
||||
User.blocks.filter = function (uid, property, set, callback) {
|
||||
User.blocks.filter = async function (uid, property, set) {
|
||||
// Given whatever is passed in, iterates through it, and removes entries made by blocked uids
|
||||
// property is optional
|
||||
if (Array.isArray(property) && typeof set === 'function' && !callback) {
|
||||
callback = set;
|
||||
if (Array.isArray(property) && typeof set === 'undefined') {
|
||||
set = property;
|
||||
property = 'uid';
|
||||
}
|
||||
@@ -139,20 +106,17 @@ module.exports = function (User) {
|
||||
const check = item.hasOwnProperty(property) ? item[property] : item;
|
||||
return ['number', 'string'].includes(typeof check);
|
||||
})) {
|
||||
return callback(null, set);
|
||||
return set;
|
||||
}
|
||||
|
||||
const isPlain = typeof set[0] !== 'object';
|
||||
User.blocks.list(uid, function (err, blocked_uids) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
const blocked_uids = await User.blocks.list(uid);
|
||||
const blockedSet = new Set(blocked_uids);
|
||||
|
||||
set = set.filter(function (item) {
|
||||
return !blocked_uids.includes(parseInt(isPlain ? item : item[property], 10));
|
||||
});
|
||||
|
||||
callback(null, set);
|
||||
set = set.filter(function (item) {
|
||||
return !blockedSet.has(parseInt(isPlain ? item : item[property], 10));
|
||||
});
|
||||
|
||||
return set;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,89 +1,64 @@
|
||||
'use strict';
|
||||
|
||||
const async = require('async');
|
||||
const _ = require('lodash');
|
||||
|
||||
const db = require('../database');
|
||||
const categories = require('../categories');
|
||||
|
||||
module.exports = function (User) {
|
||||
User.setCategoryWatchState = function (uid, cid, state, callback) {
|
||||
User.setCategoryWatchState = async function (uid, cid, state) {
|
||||
if (!(parseInt(uid, 10) > 0)) {
|
||||
return setImmediate(callback);
|
||||
return;
|
||||
}
|
||||
const isStateValid = Object.keys(categories.watchStates).some(key => categories.watchStates[key] === parseInt(state, 10));
|
||||
const isStateValid = Object.values(categories.watchStates).includes(parseInt(state, 10));
|
||||
if (!isStateValid) {
|
||||
return setImmediate(callback, new Error('[[error:invalid-watch-state]]'));
|
||||
throw new Error('[[error:invalid-watch-state]]');
|
||||
}
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
categories.exists(cid, next);
|
||||
},
|
||||
function (exists, next) {
|
||||
if (!exists) {
|
||||
return next(new Error('[[error:no-category]]'));
|
||||
}
|
||||
|
||||
db.sortedSetAdd('cid:' + cid + ':uid:watch:state', state, uid, next);
|
||||
},
|
||||
], callback);
|
||||
const exists = await categories.exists(cid);
|
||||
if (!exists) {
|
||||
throw new Error('[[error:no-category]]');
|
||||
}
|
||||
await db.sortedSetAdd('cid:' + cid + ':uid:watch:state', state, uid);
|
||||
};
|
||||
|
||||
User.getCategoryWatchState = function (uid, callback) {
|
||||
if (parseInt(uid, 10) <= 0) {
|
||||
return setImmediate(callback, null, {});
|
||||
}
|
||||
|
||||
let cids;
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
categories.getAllCidsFromSet('categories:cid', next);
|
||||
},
|
||||
function (_cids, next) {
|
||||
cids = _cids;
|
||||
categories.getWatchState(cids, uid, next);
|
||||
},
|
||||
function (states, next) {
|
||||
next(null, _.zipObject(cids, states));
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
|
||||
User.getIgnoredCategories = function (uid, callback) {
|
||||
if (parseInt(uid, 10) <= 0) {
|
||||
return setImmediate(callback, null, []);
|
||||
}
|
||||
User.getCategoriesByStates(uid, [categories.watchStates.ignoring], callback);
|
||||
};
|
||||
|
||||
User.getWatchedCategories = function (uid, callback) {
|
||||
if (parseInt(uid, 10) <= 0) {
|
||||
return setImmediate(callback, null, []);
|
||||
}
|
||||
User.getCategoriesByStates(uid, [categories.watchStates.watching], callback);
|
||||
};
|
||||
|
||||
User.getCategoriesByStates = function (uid, states, callback) {
|
||||
User.getCategoryWatchState = async function (uid) {
|
||||
if (!(parseInt(uid, 10) > 0)) {
|
||||
return categories.getAllCidsFromSet('categories:cid', callback);
|
||||
return {};
|
||||
}
|
||||
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
User.getCategoryWatchState(uid, next);
|
||||
},
|
||||
function (userState, next) {
|
||||
const cids = Object.keys(userState);
|
||||
next(null, cids.filter(cid => states.includes(userState[cid])));
|
||||
},
|
||||
], callback);
|
||||
const cids = await categories.getAllCidsFromSet('categories:cid');
|
||||
const states = await categories.getWatchState(cids, uid);
|
||||
return _.zipObject(cids, states);
|
||||
};
|
||||
|
||||
User.ignoreCategory = function (uid, cid, callback) {
|
||||
User.setCategoryWatchState(uid, cid, categories.watchStates.ignoring, callback);
|
||||
User.getIgnoredCategories = async function (uid) {
|
||||
if (!(parseInt(uid, 10) > 0)) {
|
||||
return [];
|
||||
}
|
||||
return await User.getCategoriesByStates(uid, [categories.watchStates.ignoring]);
|
||||
};
|
||||
|
||||
User.watchCategory = function (uid, cid, callback) {
|
||||
User.setCategoryWatchState(uid, cid, categories.watchStates.watching, callback);
|
||||
User.getWatchedCategories = async function (uid) {
|
||||
if (!(parseInt(uid, 10) > 0)) {
|
||||
return [];
|
||||
}
|
||||
return await User.getCategoriesByStates(uid, [categories.watchStates.watching]);
|
||||
};
|
||||
|
||||
User.getCategoriesByStates = async function (uid, states) {
|
||||
if (!(parseInt(uid, 10) > 0)) {
|
||||
return await categories.getAllCidsFromSet('categories:cid');
|
||||
}
|
||||
const userState = await User.getCategoryWatchState(uid);
|
||||
const cids = Object.keys(userState);
|
||||
return cids.filter(cid => states.includes(userState[cid]));
|
||||
};
|
||||
|
||||
User.ignoreCategory = async function (uid, cid) {
|
||||
await User.setCategoryWatchState(uid, cid, categories.watchStates.ignoring);
|
||||
};
|
||||
|
||||
User.watchCategory = async function (uid, cid) {
|
||||
await User.setCategoryWatchState(uid, cid, categories.watchStates.watching);
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user