Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for app authentication in the demo app #357

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
32 changes: 32 additions & 0 deletions apps-script/incident-response/ChatApi.gs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Creates a space in Google Chat with the provided title and members, and posts an
* initial message to it.
*
* @param {Object} formData the data submitted by the user. It should contain the fields
* title, description, and users.
* @return {string} the resource name of the new space.
*/
function handleIncident(formData) {
console.log(formData)
const appCredentialsMode = formData.appCredentials; // Get the appCredentials element
if(appCredentialsMode){
return handleIncidentWithAppCredentials(formData)
} else{
return handleIncidentWithHumanCredentials(formData)
}
}
121 changes: 121 additions & 0 deletions apps-script/incident-response/ChatApiAppCredentials.gs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/**
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

function handleIncidentWithAppCredentials(formData) {
const users = formData.users.trim().length > 0 ? formData.users.split(',') : [];
const spaceName = createChatSpaceWithAppCredentials(formData.title);
createHumanMembershipWithAppCredentials(spaceName, getUserEmail());
for (const user of users ){
createHumanMembershipWithAppCredentials(spaceName, user);
}
createMessageWithAppCredentials(spaceName, formData.description);
return spaceName;
}



function createChatSpaceWithAppCredentials(spaceName) {
try {
const service = getService_();
if (!service.hasAccess()) {
console.error(service.getLastError());
return;
}
// for private apps, the alias can be used
const my_customer_alias = "customers/my_customer"
// Specify the space to create.
const space = {
displayName: spaceName,
spaceType: 'SPACE',
customer: my_customer_alias
};
// Call Chat API with a service account to create a message.
const createdSpace = Chat.Spaces.create(
space,
{},
// Authenticate with the service account token.
{'Authorization': 'Bearer ' + service.getAccessToken()});
// Log details about the created message.
console.log(createdSpace);
return createdSpace.name;
} catch (err) {
// TODO (developer) - Handle exception.
console.log('Failed to create space with error %s', err.message);
}
}

function createMessageWithAppCredentials(spaceName, message) {
try {
const service = getService_();
if (!service.hasAccess()) {
console.error(service.getLastError());
return;
}

// Call Chat API with a service account to create a message.
const result = Chat.Spaces.Messages.create(
{'text': message},
spaceName,
{},
// Authenticate with the service account token.
{'Authorization': 'Bearer ' + service.getAccessToken()});

// Log details about the created message.
console.log(result);
} catch (err) {
// TODO (developer) - Handle exception.
console.log('Failed to create message with error %s', err.message);
}
}

function createHumanMembershipWithAppCredentials(spaceName, email){
try{
const service = getService_();
if (!service.hasAccess()) {
console.error(service.getLastError());
return;
}
const membership = {
member: {
// TODO(developer): Replace USER_NAME here
name: 'users/'+email,
// User type for the membership
type: 'HUMAN'
}
};
const result = Chat.Spaces.Members.create(
membership,
spaceName,
{},
{'Authorization': 'Bearer ' + service.getAccessToken()}
);
console.log(result)
} catch (err){
console.log('Failed to create membership with error %s', err.message)
}

}


function getService_() {
return OAuth2.createService(APP_CREDENTIALS.client_email)
.setTokenUrl('https://oauth2.googleapis.com/token')
.setPrivateKey(APP_CREDENTIALS.private_key)
.setIssuer(APP_CREDENTIALS.client_email)
.setSubject(APP_CREDENTIALS.client_email)
.setScope(APP_CREDENTIALS_SCOPES)
.setPropertyStore(PropertiesService.getScriptProperties());
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2023 Google LLC
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -23,11 +23,11 @@
* title, description, and users.
* @return {string} the resource name of the new space.
*/
function createChatSpace(formData) {
function handleIncidentWithHumanCredentials(formData) {
const users = formData.users.trim().length > 0 ? formData.users.split(',') : [];
const spaceName = setUpSpace_(formData.title, users);
addAppToSpace_(spaceName);
createMessage_(spaceName, formData.description);
const spaceName = setUpSpaceWithHumanCredentials(formData.title, users);
addAppToSpaceWithHumanCredentials(spaceName);
createMessageWithHumanCredentials(spaceName, formData.description);
return spaceName;
}

Expand All @@ -36,7 +36,7 @@ function createChatSpace(formData) {
*
* @return {string} the resource name of the new space.
*/
function setUpSpace_(displayName, users) {
function setUpSpaceWithHumanCredentials(displayName, users) {
const memberships = users.map(email => ({
member: {
name: `users/${email}`,
Expand All @@ -61,7 +61,7 @@ function setUpSpace_(displayName, users) {
*
* @return {string} the resource name of the new membership.
*/
function addAppToSpace_(spaceName) {
function addAppToSpaceWithHumanCredentials(spaceName) {
const request = {
member: {
name: "users/app",
Expand All @@ -78,7 +78,7 @@ function addAppToSpace_(spaceName) {
*
* @return {string} the resource name of the new message.
*/
function createMessage_(spaceName, text) {
function createMessageWithHumanCredentials(spaceName, text) {
const request = {
text: text
};
Expand All @@ -87,4 +87,4 @@ function createMessage_(spaceName, text) {
return message.name;
}

// [END chat_incident_response_space_creator]
// [END chat_incident_response_space_creator]
2 changes: 1 addition & 1 deletion apps-script/incident-response/ChatApp.gs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2023 Google LLC
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
13 changes: 8 additions & 5 deletions apps-script/incident-response/Consts.gs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2023 Google LLC
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -15,8 +15,11 @@
*/
// [START chat_incident_response_consts]

const PROJECT_ID = 'replace-with-your-project-id';
const VERTEX_AI_LOCATION_ID = 'us-central1';
const CLOSE_INCIDENT_COMMAND_ID = 1;
const PROJECT_ID = PROJECT_ID';
const CLOSE_INCIDENT_COMMAND_ID = 3;
const APP_CREDENTIALS = APP_CREDENTIALS;
const APP_CREDENTIALS_SCOPES = 'https://www.googleapis.com/auth/chat.bot https://www.googleapis.com/auth/chat.app.memberships https://www.googleapis.com/auth/chat.app.spaces.create';
const GEMINI_API_KEY = GEMINI_API_KEY;

// [END chat_incident_response_consts]

// [END chat_incident_response_consts]
2 changes: 1 addition & 1 deletion apps-script/incident-response/DocsApi.gs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2023 Google LLC
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
66 changes: 66 additions & 0 deletions apps-script/incident-response/GeminiApi.gs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// [START chat_incident_response_gemini]

/**
* Summarizes a Chat conversation using the Vertex AI text prediction API.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gemini API? (instead of Vertex API)

*
* @param {string} chatHistory The Chat history that will be summarized.
* @return {string} The content from the text prediction response.
*/
function summarizeChatHistory_(chatHistory) {
const prompt =
"Summarize the following conversation between Engineers resolving an incident"
+ " in a few sentences. Use only the information from the conversation.\n\n"
+ chatHistory;

const payload = {
"contents": [{
"parts": [{
"text": prompt
}]
}]
};

const fetchOptions = {
method: 'POST',
contentType: 'application/json',
payload: JSON.stringify(payload)
}
const gemini_endpoint = `https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=${GEMINI_API_KEY}`;

try {
var response = UrlFetchApp.fetch(gemini_endpoint, fetchOptions);
var responseCode = response.getResponseCode();
var responseBody = response.getContentText();

if (responseCode === 200) {
var json = JSON.parse(responseBody);
if (json.candidates && json.candidates.length > 0 && json.candidates[0].content && json.candidates[0].content.parts && json.candidates[0].content.parts.length > 0) {
return json.candidates[0].content.parts[0].text;
} else {
return "Gemini API: Unexpected response structure.";
}
} else {
return "Gemini API Error: " + responseCode + " - " + responseBody;
}
} catch (e) {
console.log("Error during API call: " + e.toString())
return 'Gemini API error, please check logs.'
}
}

// [END chat_incident_response_gemini]
8 changes: 6 additions & 2 deletions apps-script/incident-response/Index.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!--
Copyright 2023 Google LLC
Copyright 2025 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -45,6 +45,10 @@ <h1>Incident Manager</h1>
<small>This message will be posted after the space is created.</small><br/>
<textarea name="description" id="description"></textarea>
</p>
<p>
<label for="appCredentials">Use app credentials</label>
<input type="checkbox" id="appCredentials" name="appCredentials" value="true">
</p>
<p class="text-center">
<input type="submit" value="CREATE CHAT SPACE" />
</p>
Expand All @@ -59,4 +63,4 @@ <h1>Incident Manager</h1>
<?!= include('JavaScript'); ?>
</body>
</html>
<!-- [END chat_incident_response_index] -->
<!-- [END chat_incident_response_index] -->
Loading