From 584f88e0923250f2a2a044c9e98a5ba3ac74f8ac Mon Sep 17 00:00:00 2001 From: Baris Usakli Date: Tue, 3 Jul 2018 15:12:23 -0400 Subject: [PATCH] blocks WIP --- public/src/client/account/blocks.js | 3 +- src/socket.io/user/profile.js | 6 +-- src/user/blocks.js | 65 ++++++++++++++--------------- test/user.js | 24 +++++++++++ 4 files changed, 61 insertions(+), 37 deletions(-) diff --git a/public/src/client/account/blocks.js b/public/src/client/account/blocks.js index f6ef1154d0..11d656fa46 100644 --- a/public/src/client/account/blocks.js +++ b/public/src/client/account/blocks.js @@ -17,7 +17,8 @@ define('forum/account/blocks', ['forum/account/header', 'autocomplete'], functio $('.block-edit').on('click', '[data-action="toggle"]', function () { var uid = parseInt(this.getAttribute('data-uid'), 10); socket.emit('user.toggleBlock', { - uid: uid, + blockeeUid: uid, + blockerUid: ajaxify.data.uid, }, Blocks.refreshList); }); }; diff --git a/src/socket.io/user/profile.js b/src/socket.io/user/profile.js index 49e63744c6..fa76573a54 100644 --- a/src/socket.io/user/profile.js +++ b/src/socket.io/user/profile.js @@ -210,16 +210,16 @@ module.exports = function (SocketUser) { SocketUser.toggleBlock = function (socket, data, callback) { async.waterfall([ function (next) { - user.blocks.can(data.uid, next); + user.blocks.can(socket.uid, data.blockerUid, data.blockeeUid, next); }, function (can, next) { if (!can) { return next(new Error('[[error:cannot-block-privileged]]')); } - user.blocks.is(data.uid, socket.uid, next); + user.blocks.is(data.blockeeUid, data.blockerUid, next); }, function (is, next) { - user.blocks[is ? 'remove' : 'add'](data.uid, socket.uid, next); + user.blocks[is ? 'remove' : 'add'](data.blockeeUid, data.blockerUid, next); }, ], callback); }; diff --git a/src/user/blocks.js b/src/user/blocks.js index 75767e4a12..d28ea5c505 100644 --- a/src/user/blocks.js +++ b/src/user/blocks.js @@ -2,40 +2,46 @@ var async = require('async'); var db = require('../database'); -var LRU = require('lru-cache'); module.exports = function (User) { - User.blocks = { - _cache: LRU({ - max: 100, - length: function () { return 1; }, - maxAge: 0, - }), - }; + User.blocks = {}; User.blocks.is = function (targetUid, uid, callback) { - User.blocks.list(uid, function (err, blocks) { - callback(err, blocks.includes(parseInt(targetUid, 10))); - }); + db.isSortedSetMember('uid:' + uid + ':blocked_uids', String(targetUid), callback); }; - User.blocks.can = function (uid, callback) { + User.blocks.can = function (callerUid, blockerUid, blockeeUid, callback) { // Administrators and global moderators cannot be blocked - User.isAdminOrGlobalMod(uid, (err, can) => callback(err, !can)); + 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(null, false); + } + if (parseInt(callerUid, 10) !== parseInt(blockerUid, 10) && !results.isCallerAdminOrMod) { + return callback(null, false); + } + next(null, true); + }, + ], callback); }; User.blocks.list = function (uid, callback) { - if (User.blocks._cache.has(uid)) { - return setImmediate(callback, null, User.blocks._cache.get(uid)); - } - 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(uid, blocked); callback(null, blocked); }); }; @@ -45,11 +51,6 @@ module.exports = function (User) { async.apply(this.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(uid); - setImmediate(next); - }, - async.apply(User.blocks.list, uid), ], callback); }; @@ -58,11 +59,6 @@ module.exports = function (User) { async.apply(this.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(uid); - setImmediate(next); - }, - async.apply(User.blocks.list, uid), ], callback); }; @@ -77,11 +73,14 @@ module.exports = function (User) { }; 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); + const sets = uids.map(uid => 'uid:' + uid + ':blocked_uids'); + db.isMemberOfSortedSets(sets, targetUid, function (err, isMembers) { + if (err) { + return callback(err); + } + uids = uids.filter((uid, index) => isMembers[index]); + callback(null, uids); + }); }; User.blocks.filter = function (uid, property, set, callback) { diff --git a/test/user.js b/test/user.js index b29cd8c865..4ee40c61a7 100644 --- a/test/user.js +++ b/test/user.js @@ -1797,6 +1797,30 @@ describe('User', function () { }); }); + describe('.toggle()', function () { + it('should toggle block', function (done) { + socketUser.toggleBlock({ uid: 1 }, { blockerUid: 1, blockeeUid: blockeeUid }, function (err) { + assert.ifError(err); + User.blocks.is(blockeeUid, 1, function (err, blocked) { + assert.ifError(err); + assert(blocked); + done(); + }); + }); + }); + + it('should toggle block', function (done) { + socketUser.toggleBlock({ uid: 1 }, { blockerUid: 1, blockeeUid: blockeeUid }, function (err) { + assert.ifError(err); + User.blocks.is(blockeeUid, 1, function (err, blocked) { + assert.ifError(err); + assert(!blocked); + done(); + }); + }); + }); + }); + describe('.add()', function () { it('should block a uid', function (done) { User.blocks.add(blockeeUid, 1, function (err, blocked_uids) {