Skip to content
This repository has been archived by the owner on Dec 7, 2023. It is now read-only.

Group membership #47

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions group-membership/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "../configs/appsscript.eslintrc.json"
}
116 changes: 116 additions & 0 deletions group-membership/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
---
title: Scale access to external vendors and partners
TechandEco marked this conversation as resolved.
Show resolved Hide resolved
description: Share documents, events, and communications with users outside
your domain
labels: Sheets, Groups, Apps Script
material_icon: group_work
create_time: 2019-08-30
update_time: 2019-12-27
---
Contributed by Tech and Eco, follow me on
[Twitter](https://twitter.com/TechandEco)!

Use a Google Group to work cross-functionally with vendors, partners,
customers, and volunteers outside of your domain, and scale access
to work assignments and leverage security controls. You can add an external
user's Google email (this can be their own G Suite account, a G Suite user
account you created for them within your domain, or a free Gmail account) to
your G Suite Google group (not available for consumer Google Groups) via a
Google Sheet to manage users in bulk and keep track of the onboarding history.

Top 6 benefits of this solution:

1. Adds a new external user to a G Suite Google Group you create
(example: [email protected]) once, and it allows users to open all
resources that are shared with that group moving forward (calendar, files,
training site, dashboards (built on DataStudio), etc.

1. When adding one or more users to your Google Group, users can receive a
welcome email with the links they can access.
[Creating a Google Site](https://sites.google.com/new) is optional but
recommended to centralize information in a beautiful website interface.

1. The template of the welcome email is composed in a Google Doc. You
TechandEco marked this conversation as resolved.
Show resolved Hide resolved
can use seperate Google Docs for different recipients to customize
TechandEco marked this conversation as resolved.
Show resolved Hide resolved
messaging.

1. Capture the email addresses of users in your Sheet, and add them in bulk to
the desired Google Groups at a later time by changing the column "Allowed"
to "yes" for each row of users.
TechandEco marked this conversation as resolved.
Show resolved Hide resolved

1. You or members of your team, can add users to different Google Groups as
long as the person who made a copy of this sheet has
_manager_ or _owner_ rights in each of those Google Groups.

1. Removing a user from a Group (via the Google Group's interface) will revoke
their access to all resources. You can also limit documents to be available
to that group for a
[specific period of time](https://support.google.com/docs/answer/2494893?co=GENIE.Platform%3DDesktop&hl=en).

![Users are added to a Google Group via a Google Sheet](https://cdn.jsdelivr.net/gh/gsuitedevs/solutions@master/group-membership/demo.gif)

## Technology highlights

- Install a trigger with a click so the script is setup to run everytime the
Sheet is edited. To learn more visit
[this page](https://developers.google.com/apps-script/guides/triggers/installable))
TechandEco marked this conversation as resolved.
Show resolved Hide resolved
- Add members to a _Google Group for Business_ using the
[Admin Directory API](https://developers.google.com/apps-script/advanced/admin-sdk-directory)

## Try it

1. Copy the [External Sustainability Group List](https://docs.google.com/spreadsheets/d/1KJKc2DcCr2bHLCq5Judvvwuen3k3ifFY8wtQWKfHDXU/copy) from your _G Suite_ account.

1. Enter for testing purposes a _Gmail address you own_ and a Google Group you
have _rights to manage_ its membership. You can learn about
[group permissions here](https://support.google.com/groups/answer/2464975?hl=en)

> _Note_: The membership status will be populated by the words
> **Newly added** if the user was added to the group, or **Already added**
> if it recognizes the user is already a member of that group.

1. Enter “yes” in the “Allowed” column.
1. Let’s visit the code now by clicking on **Tools > Script Editor**.
1. Ensure the _Admin Directory API_ is enabled via
**Resources > Advanced Google Services**.
1. Create a trigger by clicking the clock-like icon and choosing the
“onEditInstallableTrigger” function from the drop-down to run the event on
“onOpen”
1. Return to the script page and _run the script_ by clicking the
**"Select function"** drop down >
choose **"onEditInstallableTrigger."** Then click the Run button (►).
This will create a trigger for your sheet automatically.

1. When prompted, click the **Review permissions** and click **Allow** so the
script can email on your behalf.

> _Note_: If you get a warning that **This app isn't verified** continue
> with the verification process by clicking **Advanced** and then scroll
> down and click the grey text at the bottom that begins with **Go to...**

1. Check your inbox and Google Group’s interface under it’s _members_ section.

## _[optional]_ Customize your messaging

- If you wish to change the subject lines of your emails, replace
the text in the “Email subject” column.

- If you wish to change the email template that is sent out, replace the URL
in the “Email template” column with your preferred Google Doc. If you wish
to include any of the column values in the template, enter them as such in
the template {{Column_name}} like this: _Welcome, we have added your
{{Email}} to this {{Google_Group}} in order give you access to the following
resources..._
> _Note_: If you encounter any issues with the welcome email, change the
> permission levels of the Google Doc templates to more open settings.

## Next steps

To get started with Google Apps Script, try out [the codelab][codelab]
which guides you through the creation of your first script.

You can also view the [full source code][github] of this solution on GitHub to
learn more about how it was built.

[codelab]: https://codelabs.developers.google.com/codelabs/apps-script-intro
[github]: https://github.com/gsuitedevs/solutions/blob/master/group-membership
Binary file added group-membership/demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
111 changes: 111 additions & 0 deletions group-membership/src/Code.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
var EMAIL = 'Email';
var GOOGLE_GROUP = 'Google Group';
var ALLOWED = 'Allowed';
var EMAIL_TEMPLATE_DOC_URL = 'Email template doc URL';
var EMAIL_SUBJECT = 'Email subject';
var STATUS = 'Status';

/**
* Trigger that runs on edit after being installed via the interface.
*
* @param {Object} e - onEdit trigger event.
*/
function onEditInstallableTrigger(e) {
TechandEco marked this conversation as resolved.
Show resolved Hide resolved
// Get the headers, row range and values from the active sheet.
var sheet = SpreadsheetApp.getActiveSheet();
var headers = sheet.getDataRange().offset(0, 0, 1).getValues()[0];
var range = sheet.getRange(e.range.getRow(), 1, 1, headers.length);
var row = range.getValues()[0];

// Convert the row Array into an entries Object using the headers for the
// field names.
var entries = headers.reduce(function(result, columnName, i) {
result[columnName] = row[i];
return result;
}, {});

// Update the entries Object with the status returned by addToGroup().
try {
entries[STATUS] = addToGroup(
entries[EMAIL],
entries[GOOGLE_GROUP],
entries[ALLOWED],
entries[EMAIL_TEMPLATE_DOC_URL],
entries[EMAIL_SUBJECT]
);
} catch (e) {
TechandEco marked this conversation as resolved.
Show resolved Hide resolved
// If there's an error, report that as the status.
entries[STATUS] = e;
}

// Convert the updated entries Object into a row Array.
TechandEco marked this conversation as resolved.
Show resolved Hide resolved
var rowToWrite = headers.map(function(columnName) {
return entries[columnName];
});

// setValues() receives a 2D array, so we create an array with the row
// contents.
range.setValues([rowToWrite]);
}


/**
* Trigger that runs on edit after being installed via the interface.
*
* @param {string} userEmail - email of user to add to the group.
* @param {string} groupEmail - address of Google Group to add user to.
* @param {string} allowed - 'yes' flag to add user to group.
* @param {string} emailTemplateDocUrl - Google Doc URL that serves as template
* of the welcome email sent to a user added to the group.
* @param {string} emailSubject - subject of welcome email sent to user added
* to group.
* @return {string} - status if email was sent to a user added in the sheet.
TechandEco marked this conversation as resolved.
Show resolved Hide resolved
*/
function addToGroup(userEmail, groupEmail, allowed, emailTemplateDocUrl, emailSubject) {
if (allowed.toLowerCase() != 'yes') {
return 'Not sent';
}

// If the group does not contain the user's email, add it and send an email.
var group = GroupsApp.getGroupByEmail(groupEmail);
if (!group.hasUser(userEmail)) {
// User is not part of the group, add user to the group.
var member = {email: userEmail, role: 'MEMBER'};
AdminDirectory.Members.insert(member, groupEmail);

// Send a confirmation email that the member was now added.
var docId = DocumentApp.openByUrl(emailTemplateDocUrl).getId();
var emailBody = docToHtml(docId);

// Replace the template variables like {{VARIABLE}} with real values.
emailBody = emailBody.replace('{{EMAIL}}', userEmail);
emailBody = emailBody.replace('{{GOOGLE_GROUP}}', groupEmail);

MailApp.sendEmail({
to: userEmail,
subject: emailSubject,
htmlBody: emailBody,
});

// Set the status to the current date.
return new Date();
TechandEco marked this conversation as resolved.
Show resolved Hide resolved
}
return 'Already in group';
}

/**
* Fetches a Google Doc as an HTML string.
*
* @param {string} docId - The ID of a Google Doc to fetch content from.
* @return {string} The Google Doc rendered as an HTML string.
*/
function docToHtml(docId) {
var url = 'https://docs.google.com/feeds/download/documents/export/Export?id=' +
docId + '&exportFormat=html';
var param = {
method: 'get',
headers: {'Authorization': 'Bearer ' + ScriptApp.getOAuthToken()},
muteHttpExceptions: true,
};
return UrlFetchApp.fetch(url, param).getContentText();
}
21 changes: 21 additions & 0 deletions group-membership/src/appsscript.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"timeZone": "America/Los_Angeles",
"dependencies": {
"enabledAdvancedServices": [{
"userSymbol": "AdminDirectory",
"serviceId": "admin",
"version": "directory_v1"
}]
},
"exceptionLogging": "STACKDRIVER",
"oauthScopes": [
"https://www.googleapis.com/auth/admin.directory.group.member",
"https://www.googleapis.com/auth/documents",
"https://www.googleapis.com/auth/drive.readonly",
"https://www.googleapis.com/auth/groups",
"https://www.googleapis.com/auth/script.external_request",
"https://www.googleapis.com/auth/script.scriptapp",
"https://www.googleapis.com/auth/script.send_mail",
"https://www.googleapis.com/auth/spreadsheets.currentonly"
]
}