From 4239c376c84c9816f7e774b076445ad9ad2a6d0e Mon Sep 17 00:00:00 2001
From: Julian Lam <julian@designcreateplay.com>
Date: Wed, 19 Mar 2014 10:27:02 -0400
Subject: [PATCH] truncating user list in Groups ACP page, resolved #1132.
 Refactored system groups handling

---
 public/src/forum/admin/groups.js |  3 ++
 src/controllers/admin.js         | 19 +++--------
 src/groups.js                    | 58 ++++++++++++++++++--------------
 src/socket.io/admin.js           | 14 +++-----
 4 files changed, 45 insertions(+), 49 deletions(-)

diff --git a/public/src/forum/admin/groups.js b/public/src/forum/admin/groups.js
index 435bb35d24..8546b53c4f 100644
--- a/public/src/forum/admin/groups.js
+++ b/public/src/forum/admin/groups.js
@@ -208,6 +208,9 @@ define(function() {
 				}
 			});
 		});
+
+		// Tooltips
+		$('#groups-list .members li').tooltip();
 	};
 
 	return Groups;
diff --git a/src/controllers/admin.js b/src/controllers/admin.js
index f62a4e974d..826f9e71f3 100644
--- a/src/controllers/admin.js
+++ b/src/controllers/admin.js
@@ -150,20 +150,11 @@ adminController.themes.get = function(req, res, next) {
 };
 
 adminController.groups.get = function(req, res, next) {
-	async.parallel([
-		function(next) {
-			groups.list({
-				expand: true
-			}, next);
-		},
-		function(next) {
-			groups.listSystemGroups({
-				expand: true
-			}, next);
-		}
-	], function(err, groupData) {
-		var	groups = groupData[0].concat(groupData[1]);
-
+	groups.list({
+		expand: true,
+		showSystemGroups: true,
+		truncateUserList: true
+	}, function(err, groups) {
 		res.render('admin/groups', {
 			groups: groups,
 			yourid: req.user.uid
diff --git a/src/groups.js b/src/groups.js
index 4b0ba0ea4a..ddcea8801d 100644
--- a/src/groups.js
+++ b/src/groups.js
@@ -15,18 +15,18 @@
 		db.getObjectValues('group:gid', function (err, gids) {
 			if (gids.length > 0) {
 				async.map(gids, function (gid, next) {
-					Groups.get(gid, {
-						expand: options.expand
-					}, next);
+					Groups.get(gid, options, next);
 				}, function (err, groups) {
-					// Remove deleted and hidden groups from this list
-					callback(err, groups.filter(function (group) {
-						if (parseInt(group.deleted, 10) === 1 || parseInt(group.hidden, 10) === 1) {
+					// Remove system, hidden, or deleted groups from this list
+					groups = groups.filter(function (group) {
+						if (group.deleted || (group.hidden && !group.system) || (!options.showSystemGroups && group.system)) {
 							return false;
 						} else {
 							return true;
 						}
-					}));
+					});
+
+					callback(err, groups);
 				});
 			} else {
 				callback(null, []);
@@ -34,32 +34,30 @@
 		});
 	};
 
-	Groups.listSystemGroups = function(options, callback) {
-		var	systemGroups = ['administrators', 'registered-users'],
-			humanNames = ['Administrators', 'Registered Users'];
-
-		async.map(systemGroups, function(groupName, next) {
-			Groups.getByGroupName(groupName, options, function(err, groupObj) {
-				groupObj.name = humanNames[systemGroups.indexOf(groupObj.name)];
-				next(err, groupObj);
-			});
-		}, callback);
-	};
-
 	Groups.get = function(gid, options, callback) {
+		var	truncated = false,
+			numUsers;
+
 		async.parallel({
 			base: function (next) {
 				db.getObject('gid:' + gid, next);
 			},
 			users: function (next) {
 				db.getSetMembers('gid:' + gid + ':members', function (err, uids) {
-					if (options.expand) {
-						if (err) {
-							return next(err);
+					if (err) {
+						return next(err);
+					}
+
+					if (options.truncateUserList) {
+						if (uids.length > 4) {
+							numUsers = uids.length;
+							uids.length = 4;
+							truncated = true;
 						}
+					}
 
+					if (options.expand) {
 						async.map(uids, user.getUserData, next);
-
 					} else {
 						next(err, uids);
 					}
@@ -72,8 +70,13 @@
 
 			results.base.count = results.users.length;
 			results.base.members = results.users;
+			results.base.memberCount = numUsers || results.users.length;
 
-			results.base.deletable = results.base.hidden !== '1';
+			results.base.deleted = !!parseInt(results.base.deleted, 10);
+			results.base.hidden = !!parseInt(results.base.hidden, 10);
+			results.base.system = !!parseInt(results.base.system, 10);
+			results.base.deletable = !results.base.system;
+			results.base.truncated = truncated;
 
 			callback(err, results.base);
 		});
@@ -197,6 +200,10 @@
 			return callback(new Error('name-too-short'));
 		}
 
+		if (name === 'administrators' || name === 'registered-users') {
+			var system = true;
+		}
+
 		Groups.exists(name, function (err, exists) {
 			if (!exists) {
 				db.incrObjectField('global', 'nextGid', function (err, gid) {
@@ -207,7 +214,8 @@
 							name: name,
 							description: description,
 							deleted: '0',
-							hidden: '0'
+							hidden: '0',
+							system: system ? '1' : '0'
 						};
 
 						db.setObject('gid:' + gid, groupData, function(err) {
diff --git a/src/socket.io/admin.js b/src/socket.io/admin.js
index 67ce00ae3c..003ed793d3 100644
--- a/src/socket.io/admin.js
+++ b/src/socket.io/admin.js
@@ -266,20 +266,14 @@ SocketAdmin.categories.setGroupPrivilege = function(socket, data, callback) {
 };
 
 SocketAdmin.categories.groupsList = function(socket, cid, callback) {
-	async.parallel({
-		groups: function(next) {
-			groups.list({expand:false}, next);
-		},
-		system: function(next) {
-			groups.listSystemGroups({expand: false}, next);
-		}
-	}, function(err, results) {
+	groups.list({
+		expand: false,
+		showSystemGroups: true
+	}, function(err, data) {
 		if(err) {
 			return callback(err);
 		}
 
-		var	data = results.groups.concat(results.system);
-
 		async.map(data, function(groupObj, next) {
 			CategoryTools.groupPrivileges(cid, groupObj.gid, function(err, privileges) {
 				if(err) {