update groups join to take array of group names (#6834)
* allow groups.join to take an array of group names * pass an array to groups.join/leave in privileges * split up groups/membership * add hits/miss to group cache * fix typov1.18.x
parent
523d68c640
commit
b57db7fd8e
@ -0,0 +1,48 @@
|
||||
'use strict';
|
||||
|
||||
var pubsub = require('../pubsub');
|
||||
var LRU = require('lru-cache');
|
||||
|
||||
var cache = LRU({
|
||||
max: 40000,
|
||||
maxAge: 0,
|
||||
});
|
||||
cache.hits = 0;
|
||||
cache.misses = 0;
|
||||
|
||||
module.exports = function (Groups) {
|
||||
Groups.cache = cache;
|
||||
|
||||
pubsub.on('group:cache:reset', function () {
|
||||
localReset();
|
||||
});
|
||||
|
||||
pubsub.on('group:cache:del', function (data) {
|
||||
if (data && data.groupNames) {
|
||||
data.groupNames.forEach(function (groupName) {
|
||||
cache.del(data.uid + ':' + groupName);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Groups.resetCache = function () {
|
||||
pubsub.publish('group:cache:reset');
|
||||
localReset();
|
||||
};
|
||||
|
||||
function localReset() {
|
||||
cache.reset();
|
||||
cache.hits = 0;
|
||||
cache.misses = 0;
|
||||
}
|
||||
|
||||
Groups.clearCache = function (uid, groupNames) {
|
||||
if (!Array.isArray(groupNames)) {
|
||||
groupNames = [groupNames];
|
||||
}
|
||||
pubsub.publish('group:cache:del', { uid: uid, groupNames: groupNames });
|
||||
groupNames.forEach(function (groupName) {
|
||||
cache.del(uid + ':' + groupName);
|
||||
});
|
||||
};
|
||||
};
|
@ -0,0 +1,124 @@
|
||||
'use strict';
|
||||
|
||||
const async = require('async');
|
||||
const winston = require('winston');
|
||||
|
||||
const db = require('../database');
|
||||
const user = require('../user');
|
||||
const plugins = require('../plugins');
|
||||
|
||||
module.exports = function (Groups) {
|
||||
Groups.join = function (groupNames, uid, callback) {
|
||||
callback = callback || function () {};
|
||||
|
||||
if (!groupNames) {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
}
|
||||
|
||||
if (!Array.isArray(groupNames)) {
|
||||
groupNames = [groupNames];
|
||||
}
|
||||
|
||||
if (!uid) {
|
||||
return callback(new Error('[[error:invalid-uid]]'));
|
||||
}
|
||||
var isAdmin;
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
async.parallel({
|
||||
isMembers: async.apply(Groups.isMemberOfGroups, uid, groupNames),
|
||||
exists: async.apply(Groups.exists, groupNames),
|
||||
isAdmin: async.apply(user.isAdministrator, uid),
|
||||
}, next);
|
||||
},
|
||||
function (results, next) {
|
||||
isAdmin = results.isAdmin;
|
||||
|
||||
var groupsToCreate = groupNames.filter(function (groupName, index) {
|
||||
return groupName && !results.exists[index];
|
||||
});
|
||||
|
||||
groupNames = groupNames.filter(function (groupName, index) {
|
||||
return !results.isMembers[index];
|
||||
});
|
||||
|
||||
if (!groupNames.length) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
createNonExistingGroups(groupsToCreate, next);
|
||||
},
|
||||
function (next) {
|
||||
var tasks = [
|
||||
async.apply(db.sortedSetsAdd, groupNames.map(groupName => 'group:' + groupName + ':members'), Date.now(), uid),
|
||||
async.apply(db.incrObjectField, groupNames.map(groupName => 'group:' + groupName), 'memberCount'),
|
||||
];
|
||||
if (isAdmin) {
|
||||
tasks.push(async.apply(db.setsAdd, groupNames.map(groupName => 'group:' + groupName + ':owners'), uid));
|
||||
}
|
||||
|
||||
async.parallel(tasks, next);
|
||||
},
|
||||
function (results, next) {
|
||||
Groups.clearCache(uid, groupNames);
|
||||
Groups.getGroupsFields(groupNames, ['name', 'hidden', 'memberCount'], next);
|
||||
},
|
||||
function (groupData, next) {
|
||||
var visibleGroups = groupData.filter(function (groupData) {
|
||||
return groupData && parseInt(groupData.hidden, 10) !== 1;
|
||||
});
|
||||
|
||||
if (visibleGroups.length) {
|
||||
db.sortedSetAdd('groups:visible:memberCount', visibleGroups.map(groupData => groupData.memberCount), visibleGroups.map(groupData => groupData.name), next);
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
},
|
||||
function (next) {
|
||||
setGroupTitleIfNotSet(groupNames, uid, next);
|
||||
},
|
||||
function (next) {
|
||||
plugins.fireHook('action:group.join', {
|
||||
groupNames: groupNames,
|
||||
uid: uid,
|
||||
});
|
||||
next();
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
|
||||
function createNonExistingGroups(groupsToCreate, callback) {
|
||||
if (!groupsToCreate.length) {
|
||||
return setImmediate(callback);
|
||||
}
|
||||
async.eachSeries(groupsToCreate, function (groupName, next) {
|
||||
Groups.create({
|
||||
name: groupName,
|
||||
hidden: 1,
|
||||
}, function (err) {
|
||||
if (err && err.message !== '[[error:group-already-exists]]') {
|
||||
winston.error('[groups.join] Could not create new hidden group', err);
|
||||
return next(err);
|
||||
}
|
||||
next();
|
||||
});
|
||||
}, callback);
|
||||
}
|
||||
|
||||
function setGroupTitleIfNotSet(groupNames, uid, callback) {
|
||||
groupNames = groupNames.filter(function (groupName) {
|
||||
return groupName !== 'registered-users' && !Groups.isPrivilegeGroup(groupName);
|
||||
});
|
||||
if (!groupNames.length) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
db.getObjectField('user:' + uid, 'groupTitle', function (err, currentTitle) {
|
||||
if (err || currentTitle || currentTitle === '') {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
user.setUserField(uid, 'groupTitle', JSON.stringify(groupNames), callback);
|
||||
});
|
||||
}
|
||||
};
|
@ -0,0 +1,122 @@
|
||||
'use strict';
|
||||
|
||||
const async = require('async');
|
||||
|
||||
const db = require('../database');
|
||||
const user = require('../user');
|
||||
const plugins = require('../plugins');
|
||||
|
||||
module.exports = function (Groups) {
|
||||
Groups.leave = function (groupNames, uid, callback) {
|
||||
callback = callback || function () {};
|
||||
|
||||
if (!Array.isArray(groupNames)) {
|
||||
groupNames = [groupNames];
|
||||
}
|
||||
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
async.parallel({
|
||||
isMembers: async.apply(Groups.isMemberOfGroups, uid, groupNames),
|
||||
exists: async.apply(Groups.exists, groupNames),
|
||||
}, next);
|
||||
},
|
||||
function (result, next) {
|
||||
groupNames = groupNames.filter(function (groupName, index) {
|
||||
return result.isMembers[index] && result.exists[index];
|
||||
});
|
||||
|
||||
if (!groupNames.length) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
async.parallel([
|
||||
async.apply(db.sortedSetRemove, groupNames.map(groupName => 'group:' + groupName + ':members'), uid),
|
||||
async.apply(db.setRemove, groupNames.map(groupName => 'group:' + groupName + ':owners'), uid),
|
||||
async.apply(db.decrObjectField, groupNames.map(groupName => 'group:' + groupName), 'memberCount'),
|
||||
], next);
|
||||
},
|
||||
function (results, next) {
|
||||
Groups.clearCache(uid, groupNames);
|
||||
Groups.getGroupsFields(groupNames, ['name', 'hidden', 'memberCount'], next);
|
||||
},
|
||||
function (groupData, next) {
|
||||
if (!groupData) {
|
||||
return callback();
|
||||
}
|
||||
var tasks = [];
|
||||
|
||||
var emptyPrivilegeGroups = groupData.filter(function (groupData) {
|
||||
return groupData && Groups.isPrivilegeGroup(groupData.name) && parseInt(groupData.memberCount, 10) === 0;
|
||||
});
|
||||
if (emptyPrivilegeGroups.length) {
|
||||
tasks.push(async.apply(Groups.destroy, emptyPrivilegeGroups));
|
||||
}
|
||||
|
||||
var visibleGroups = groupData.filter(function (groupData) {
|
||||
return groupData && parseInt(groupData.hidden, 10) !== 1;
|
||||
});
|
||||
if (visibleGroups.length) {
|
||||
tasks.push(async.apply(db.sortedSetAdd, 'groups:visible:memberCount', visibleGroups.map(groupData => groupData.memberCount), visibleGroups.map(groupData => groupData.name)));
|
||||
}
|
||||
|
||||
async.parallel(tasks, function (err) {
|
||||
next(err);
|
||||
});
|
||||
},
|
||||
function (next) {
|
||||
clearGroupTitleIfSet(groupNames, uid, next);
|
||||
},
|
||||
function (next) {
|
||||
plugins.fireHook('action:group.leave', {
|
||||
groupNames: groupNames,
|
||||
uid: uid,
|
||||
});
|
||||
next();
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
|
||||
function clearGroupTitleIfSet(groupNames, uid, callback) {
|
||||
groupNames = groupNames.filter(function (groupName) {
|
||||
return groupName !== 'registered-users' && !Groups.isPrivilegeGroup(groupName);
|
||||
});
|
||||
if (!groupNames.length) {
|
||||
return callback();
|
||||
}
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
user.getUserData(uid, next);
|
||||
},
|
||||
function (userData, next) {
|
||||
var newTitleArray = userData.groupTitleArray.filter(function (groupTitle) {
|
||||
return !groupNames.includes(groupTitle);
|
||||
});
|
||||
|
||||
if (newTitleArray.length) {
|
||||
db.setObjectField('user:' + uid, 'groupTitle', JSON.stringify(newTitleArray), next);
|
||||
} else {
|
||||
db.deleteObjectField('user:' + uid, 'groupTitle', next);
|
||||
}
|
||||
},
|
||||
], callback);
|
||||
}
|
||||
|
||||
Groups.leaveAllGroups = function (uid, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
db.getSortedSetRange('groups:createtime', 0, -1, next);
|
||||
},
|
||||
function (groups, next) {
|
||||
async.parallel([
|
||||
function (next) {
|
||||
Groups.leave(groups, uid, next);
|
||||
},
|
||||
function (next) {
|
||||
Groups.rejectMembership(groups, uid, next);
|
||||
},
|
||||
], next);
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
};
|
Loading…
Reference in New Issue