Files
NodeBB/src/user/blocks.js

114 lines
4.0 KiB
JavaScript
Raw Normal View History

'use strict';
2019-10-03 23:31:42 -04:00
const db = require('../database');
const plugins = require('../plugins');
const cacheCreate = require('../cache/lru');
module.exports = function (User) {
2018-07-03 18:43:29 -04:00
User.blocks = {
_cache: cacheCreate({
name: 'user:blocks',
2018-07-03 18:43:29 -04:00
max: 100,
Update to lru-cache@^7 (#10815) * chore(deps): bump lru-cache from 6.0.0 to 7.13.1 in /install Bumps [lru-cache](https://github.com/isaacs/node-lru-cache) from 6.0.0 to 7.13.1. - [Release notes](https://github.com/isaacs/node-lru-cache/releases) - [Changelog](https://github.com/isaacs/node-lru-cache/blob/main/CHANGELOG.md) - [Commits](https://github.com/isaacs/node-lru-cache/compare/v6.0.0...v7.13.1) --- updated-dependencies: - dependency-name: lru-cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> * fix(lru-cache): remove unneeded `length` params for cache creation, as `maxSize` was not used in those init calls, also renamed some methods to match new method names in lru-cache [breaking] Added deprecation notices for old params * fix: replace three direct calls to lru-cache with call to cacheCreate, moved cache creation call in uploads to run on first init as config is not populated at lib init * test: move configs init above cache reset calls in databasemock * move some more code above cache clear * refactor: remove unused * test: lru * test: more debug * test: on more test * use await helpers.uploadFile * fix: tests remove logs * fix: acp cache page * fix: add in one more guard again cache instantiation with `length` prop but no `maxSize` prop * fix(deps): bump markdown Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Barış Soner Uşaklı <barisusakli@gmail.com>
2022-08-10 13:24:16 -04:00
ttl: 0,
2018-07-03 18:43:29 -04:00
}),
};
User.blocks.is = async function (targetUid, uids) {
const isArray = Array.isArray(uids);
uids = isArray ? uids : [uids];
const blocks = await User.blocks.list(uids);
const isBlocked = uids.map((uid, index) => blocks[index] && blocks[index].includes(parseInt(targetUid, 10)));
return isArray ? isBlocked : isBlocked[0];
};
User.blocks.can = async function (callerUid, blockerUid, blockeeUid, type) {
// Guests can't block
if (blockerUid === 0 || blockeeUid === 0) {
throw new Error('[[error:cannot-block-guest]]');
} else if (blockerUid === blockeeUid) {
throw new Error('[[error:cannot-block-self]]');
}
2018-05-04 12:39:00 -04:00
// Administrators and global moderators cannot be blocked
// Only admins/mods can block users as another user
const [isCallerAdminOrMod, isBlockeeAdminOrMod] = await Promise.all([
User.isAdminOrGlobalMod(callerUid),
User.isAdminOrGlobalMod(blockeeUid),
]);
if (isBlockeeAdminOrMod && type === 'block') {
throw new Error('[[error:cannot-block-privileged]]');
}
if (parseInt(callerUid, 10) !== parseInt(blockerUid, 10) && !isCallerAdminOrMod) {
2019-09-15 02:14:51 -04:00
throw new Error('[[error:no-privileges]]');
}
2018-05-04 12:39:00 -04:00
};
User.blocks.list = async function (uids) {
const isArray = Array.isArray(uids);
uids = (isArray ? uids : [uids]).map(uid => parseInt(uid, 10));
const cachedData = {};
const unCachedUids = User.blocks._cache.getUnCachedKeys(uids, cachedData);
if (unCachedUids.length) {
const unCachedData = await db.getSortedSetsMembers(unCachedUids.map(uid => `uid:${uid}:blocked_uids`));
unCachedUids.forEach((uid, index) => {
cachedData[uid] = (unCachedData[index] || []).map(uid => parseInt(uid, 10));
User.blocks._cache.set(uid, cachedData[uid]);
});
2018-07-03 18:43:29 -04:00
}
const result = uids.map(uid => cachedData[uid] || []);
return isArray ? result.slice() : result[0];
};
User.blocks.add = async function (targetUid, uid) {
await User.blocks.applyChecks('block', targetUid, uid);
2021-02-03 23:59:08 -07:00
await db.sortedSetAdd(`uid:${uid}:blocked_uids`, Date.now(), targetUid);
await User.incrementUserFieldBy(uid, 'blocksCount', 1);
User.blocks._cache.del(parseInt(uid, 10));
plugins.hooks.fire('action:user.blocks.add', { uid: uid, targetUid: targetUid });
};
User.blocks.remove = async function (targetUid, uid) {
await User.blocks.applyChecks('unblock', targetUid, uid);
2021-02-03 23:59:08 -07:00
await db.sortedSetRemove(`uid:${uid}:blocked_uids`, targetUid);
await User.decrementUserFieldBy(uid, 'blocksCount', 1);
User.blocks._cache.del(parseInt(uid, 10));
plugins.hooks.fire('action:user.blocks.remove', { uid: uid, targetUid: targetUid });
};
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) {
2021-02-03 23:59:08 -07:00
throw new Error(`[[error:already-${isBlock ? 'blocked' : 'unblocked'}]]`);
}
2018-04-27 12:51:04 -04:00
};
User.blocks.filterUids = async function (targetUid, uids) {
const isBlocked = await User.blocks.is(targetUid, uids);
return uids.filter((uid, index) => !isBlocked[index]);
2018-05-30 16:29:40 -04:00
};
User.blocks.filter = async function (uid, property, set) {
2018-04-20 14:48:10 -04:00
// Given whatever is passed in, iterates through it, and removes entries made by blocked uids
2018-04-20 13:49:23 -04:00
// property is optional
if (Array.isArray(property) && typeof set === 'undefined') {
2018-04-20 13:49:23 -04:00
set = property;
property = 'uid';
}
2018-07-03 18:43:29 -04:00
if (!Array.isArray(set) || !set.length) {
return set;
}
2018-04-20 13:49:23 -04:00
const isPlain = typeof set[0] !== 'object';
const blocked_uids = await User.blocks.list(uid);
const blockedSet = new Set(blocked_uids);
2018-07-03 18:43:29 -04:00
2021-02-04 00:01:39 -07:00
set = set.filter(item => !blockedSet.has(parseInt(isPlain ? item : (item && item[property]), 10)));
const data = await plugins.hooks.fire('filter:user.blocks.filter', { set: set, property: property, uid: uid, blockedSet: blockedSet });
return data.set;
};
};