Skip to content

Instantly share code, notes, and snippets.

@farukcan
Created May 26, 2023 08:49
Show Gist options
  • Save farukcan/2c4f41475bd6bed225a8b822bc9e1b6e to your computer and use it in GitHub Desktop.
Save farukcan/2c4f41475bd6bed225a8b822bc9e1b6e to your computer and use it in GitHub Desktop.
App Script Chat Bot Sample
// 1) Copy or Duplicate this spreadsheet (and this AppsScript project)
//
// 2) Run "setup" function once
// - Use the menu above.
//
// 3) Create Google Cloud Service Project. And copy the Project Number.
//
// 4) This > Project Settings > Set GCM project number
//
// 5) Add the line "chat": {} to your manifest file. (IMPORTANT)
//
// 6) Setup 0Auth : https://github.com/googleworkspace/apps-script-oauth2
//
// 6) Deploy
// - Select type "Web App" and "Add-on" (both)
// - Set description "v1"
// - Set "Who can access" to "Anyone"
//
// 7) Copy "Deployment Id" and "Web App URL" you will use them.
// - Check the Web APP URL, is it working?
// - "message" key must equals to "working"
// - "setup" key must not equals to "null"
//
// 8) Enable Google Chat API on console.cloud.google.com
// - Use search to find "Google Chat API" and press Enable button.
//
// 9) Go to APIs > Google Chat API > Credentials and Create a service account.
// - Choose a account name and type a description for it. (Ex: Unity GChat )
// - Click to "Create and Continue"
// - Select Role : "Basic > Owner" and Click "Continue"
// - No need to grant user access, just Click to "Done".
//
// 10) Go to APIs > Google Chat API > Configuration and fill the form.
// - Set App Name (Ex: Unity GChat)
// - Set Avatar URL (if you have not, use https://www.gstatic.com/images/branding/product/1x/chat_48dp.png )
// - Set Description. (Ex: Unity GChat allows to talk with Unity)
// - Set Functionality
// * Receive 1:1 messages => checked
// * Join spaces and group conversations => checked
// - Set Connection Settings
// * Choose "App Script Project" option
// * Paste "Deployment Id" to textbox.
// - Set Visibility
// * Add your email adresses to see the bot.
// * Add your domain if you have google workspace.
//
// 11) Create space and your providers and bot to the group..
// ####################
// # Setup
// ####################
function setup(){ // please select "setup" function and run it once.
PropertiesService.getDocumentProperties().setProperty("setup",true);
}
// ####################
// # API
// ####################
// - handle GET method
function doGet(request) {
var output = ContentService.createTextOutput();
output.setMimeType(ContentService.MimeType.JSON);
output.append(JSON.stringify({
message: "working",
setup : PropertiesService.getDocumentProperties().getProperty("setup"),
chat : PropertiesService.getDocumentProperties().getProperty("chat")
}));
return output;
}
// - handle POST method
function doPost(request){
var json = { ok: false, request: request };
if(!request.postData){
json.error = "No post data";
}else if(request.postData.type != 'application/json'){
json.error = "Invalid json body";
}else{
json.input = JSON.parse(request.postData.contents);
if(request.parameters.type){ // Ex: exec?type=create
var type = request.parameters.type;
if(type=="create") createThread(json);
else if(type=="post") postToThread(json);
else if(type=="fetch") fetchThread(json);
else json.error ="Invalid type";
}else{
json.error = "Type parameter is required";
}
}
return ContentService.createTextOutput(JSON.stringify(json)).setMimeType(ContentService.MimeType.JSON);
}
// - exec?type=create
function createThread(json){
var name = "User (No Name)";
if(json.input.name){
name = json.input.name;
}
var response = postMessage({
text: name + " created a thread."
});
json.responseForThread = JSON.parse(response.getContentText());
json.thread = json.responseForThread.thread.name;
response = postMessage({
text: name + " : " + json.input.message,
messageReplyOption : "REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD",
thread : {
name : json.thread
}
});
json.responseForMessage = JSON.parse(response.getContentText());
json.ok = true;
json.message = "Thread created";
}
// - exec?type=post
function postToThread(json){
var name = "User (No Name)";
if(json.input.name){
name = json.input.name;
}
if(json.input.thread){
var response = postMessage({
text: name + " : " + json.input.message,
messageReplyOption : "REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD",
thread : {
name : json.input.thread
}
});
json.responseForMessage = JSON.parse(response.getContentText());
json.ok = true;
json.message = "Posted to the thread";
}else{
json.error ="thread parameter is required";
}
}
// - exec?type=fetch
function fetchThread(json){
json.ok = true;
json.message = "Thread fetched";
if(json.input.thread){
//var spaceId = PropertiesService.getDocumentProperties().getProperty("space");
var service = createService();
var url = 'https://chat.googleapis.com/v1/spaces/AAAAGZq2WUk/messages/9-lnyxdLHFU.9-lnyxdLHFU'; // test
//url +="?filter=" + encodeURI("thread.name = " + json.input.thread);
var response = UrlFetchApp.fetch(url, {
method: 'get',
headers: { 'Authorization': 'Bearer ' + service.getAccessToken() }
});
json.responseForMessage = JSON.parse(response.getContentText());
json.ok = true;
json.message = "Posted to the thread";
}else{
json.error ="thread parameter is required";
}
}
// ####################
// # Bot
// ####################
function onMessage(event) {
var name = "";
var message = "";
if (event.space.type == "DM") {
message = "DM is not allowed."
} else {
name = event.user.displayName;
message = name + " said \"" + event.message.text + "\". Please use threads. ";
}
return { "text": message };
}
function onAddToSpace(event) {
var message = "";
if (event.space.singleUserBotDm) {
message = "Thank you for adding me to a DM, " + event.user.displayName + "!";
} else {
message = "Thank you for adding me to " +
(event.space.displayName ? event.space.displayName : "this chat");
}
if (event.message) {
// Bot added through @mention.
message = message + " and you said: \"" + event.message.text + "\"";
}
PropertiesService.getDocumentProperties().setProperty("space",event.space.name);
return { "text": message };
}
var SCOPE = 'https://www.googleapis.com/auth/chat.messages';
var TOKEN_URL = 'https://accounts.google.com/o/oauth2/token';
// The values below are copied from the JSON file downloaded upon
// service account creation.
// For SERVICE_ACCOUNT_PRIVATE_KEY, remember to include the BEGIN and END lines of the private key
var SERVICE_ACCOUNT_PRIVATE_KEY = '--required--';
var SERVICE_ACCOUNT_EMAIL = '--required--';
// https://developers.google.com/chat/how-tos/apps-script#async_messages
function createService(){
var service = OAuth2.createService('chat')
.setTokenUrl(TOKEN_URL)
.setPrivateKey(SERVICE_ACCOUNT_PRIVATE_KEY)
.setClientId(SERVICE_ACCOUNT_EMAIL)
.setPropertyStore(PropertiesService.getUserProperties())
.setScope(SCOPE);
if (!service.hasAccess()) {
Logger.log('Authentication error: %s', service.getLastError());
return null;
}
return service;
}
// Posts a message into the given space ID via the API, using
// service account authentication.
// https://developers.google.com/chat/api/reference/rest/v1/spaces.messages/create
function postMessage(message) {
var spaceId = PropertiesService.getDocumentProperties().getProperty("space");
var service = createService();
var url = 'https://chat.googleapis.com/v1/' + spaceId + '/messages';
if(message.messageReplyOption){
url += '?messageReplyOption=' + message.messageReplyOption;
delete message.messageReplyOption;
}
return UrlFetchApp.fetch(url, {
method: 'post',
headers: { 'Authorization': 'Bearer ' + service.getAccessToken() },
contentType: 'application/json',
payload: JSON.stringify(message),
});
}
function testMessage(){
postMessage({
text: "Hello! It's a test message."
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment