Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Get
/**
* Recursively gets all groups that a given user/group is a member
* of, either directly or indirectly, in a GWS domain.
*
* -OR-
*
* checks whether user/group is a member of provided group,
* both tasks support external users to the domain.
* Uses the AdminDirectory advanced service, and should be invoked by domain Admins!
*
* Article: https://pablofelip.online/google-groups-membership-recursively-appsscript
* Pablo Felip (@pfelipm)
*
* @param {string} userGroupEmail Email of user or group
* @param {string} [group] Group to check membership in (optional, if provided, behaviour & returned result are different)
* @return {Array|Boolean} Sorted array of group email addresses, empty if no memberships found or TRUE/FALSE
*/
function checkMembership(userGroupEmail, groupEmail) {
/**
* Helper function to retrieve groups that a given user or group is a direct-member of
* @param {string} email Email of user or group
* @return {Array] Array of group email addresses
*/
const getDirectGroups = (email) => {
let token, groups = [];
try {
do {
response = AdminDirectory.Groups.list({ userKey: email, maxResults: 200, pageToken: token });
if (response.groups) groups = [...groups, ...response.groups.map(group => group.email)];
token = response.token
} while (token);
} catch (e) {
// Exception if not a member of any group, we'll return the default empty array!
}
return groups;
};
console.info(`[START] Finding group memberships for: "${userGroupEmail}"`);
const t1 = new Date().getTime();
/**
* IIFE that performs a recursive membership search
* @param {Array} groups Array of groups to check
* @return {Array} Array of group email addresses, can contain duplicates
*/
let allGroups = (seekGroups = (groups) => {
if (groups.length == 0) {
// Base case, we have no problem to solve here!
console.info('Empty array of groups to inspect, nothing to do.');
return [];
} else if (groups.length == 1) {
// [A] general case → complexity reduction [depth]
console.info(`Finding memberships for: ${groups[0]}...`);
return [groups[0], ...seekGroups(getDirectGroups(groups[0]))];
} else if (groups.length > 1) {
// [B] general case → complexity reduction [width]
console.info(`Splitting problem → ${groups.length} groups left, ["${groups[0]}", ...rest].`);
return [...seekGroups([groups.shift()]), ...seekGroups(groups)];
}
})(getDirectGroups(userGroupEmail));
// Remove (possible) duplicates & sort list of group emails
allGroups = allGroups.filter((group, index, groups) => groups.indexOf(group) == index).sort();
const t2 = new Date().getTime();
if (!groupEmail) {
// Return array of groups that provided user/group is a member of
console.info(`[END] "${userGroupEmail}" is a member of ${allGroups.length} groups (${t2 - t1} ms).`, '\n', allGroups);
return allGroups;
} else {
// Return membership to provided group (TRUE/FALSE)
const isMember = allGroups.some(group => group == groupEmail);
console.info(`[END] "${userGroupEmail}" ${isMember ? 'is a' : 'is not a'} member of "${groupEmail}" (${t2 - t1} ms)`);
return isMember;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment