Skip to content

Commit dc54846

Browse files
authored
Add Cloud Functions Slack (Slash Command) sample. (GoogleCloudPlatform#151)
* Add Cloud Functions Slack Slash Command sample. * Couple of fixes. * Update Readme. * Small fixes. * Add tests for Slack sample. * Make lint happy. * Make lint happy.
1 parent 7cfbb9d commit dc54846

File tree

9 files changed

+456
-28
lines changed

9 files changed

+456
-28
lines changed

datastore/concepts.js

+27-27
Original file line numberDiff line numberDiff line change
@@ -165,33 +165,33 @@ Entity.prototype.testEntityWithParent = function (callback) {
165165
Entity.prototype.testProperties = function (callback) {
166166
// jshint camelcase:false
167167
// [START properties]
168-
var task = [
169-
{
170-
name: 'type',
171-
value: 'Personal'
172-
},
173-
{
174-
name: 'created',
175-
value: new Date()
176-
},
177-
{
178-
name: 'done',
179-
value: false
180-
},
181-
{
182-
name: 'priority',
183-
value: 4
184-
},
185-
{
186-
name: 'percent_complete',
187-
value: 10.0
188-
},
189-
{
190-
name: 'description',
191-
value: 'Learn Cloud Datastore',
192-
excludeFromIndexes: true
193-
}
194-
];
168+
var task = [
169+
{
170+
name: 'type',
171+
value: 'Personal'
172+
},
173+
{
174+
name: 'created',
175+
value: new Date()
176+
},
177+
{
178+
name: 'done',
179+
value: false
180+
},
181+
{
182+
name: 'priority',
183+
value: 4
184+
},
185+
{
186+
name: 'percent_complete',
187+
value: 10.0
188+
},
189+
{
190+
name: 'description',
191+
value: 'Learn Cloud Datastore',
192+
excludeFromIndexes: true
193+
}
194+
];
195195
// [END properties]
196196

197197
this.datastore.save({

datastore/tasks.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ function addTask (description, callback) {
7272

7373
datastore.save({
7474
key: taskKey,
75-
data: [
75+
data: [
7676
{
7777
name: 'created',
7878
value: new Date().toJSON()

functions/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,4 @@ environment.
3232
* [Modules](module/)
3333
* [OCR (Optical Character Recognition)](ocr/)
3434
* [SendGrid](sendgrid/)
35+
* [Slack](slack/)

functions/slack/.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
node_modules
2+
config.json
3+
test.js
4+
test/

functions/slack/README.md

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<img src="https://avatars2.githubusercontent.com/u/2810941?v=3&s=96" alt="Google Cloud Platform logo" title="Google Cloud Platform" align="right" height="96" width="96"/>
2+
3+
# Google Cloud Functions Slack Slash Command sample
4+
5+
This tutorial demonstrates using Cloud Functions to implement a Slack Slash
6+
Command that searches the Google Knowledge Graph API.
7+
8+
View the [source code][code].
9+
10+
[code]: index.js
11+
12+
## Deploy and Test
13+
14+
Read the tutorial at https://cloud.google.com/functions/docs/tutorials/slack

functions/slack/config.default.json

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"SLACK_TOKEN": "[YOUR_SLACK_TOKEN]",
3+
"KG_API_KEY": "[YOUR_KG_API_KEY]"
4+
}

functions/slack/index.js

+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
// Copyright 2016, Google, Inc.
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
'use strict';
15+
16+
// [START setup]
17+
var config = require('./config.json');
18+
var googleapis = require('googleapis');
19+
20+
// Get a reference to the Knowledge Graph Search component
21+
var kgsearch = googleapis.kgsearch('v1');
22+
// [END setup]
23+
24+
// [START formatSlackMessage]
25+
/**
26+
* Format the Knowledge Graph API response into a richly formatted Slack message.
27+
*
28+
* @param {string} query The user's search query.
29+
* @param {Object} response The response from the Knowledge Graph API.
30+
* @returns {Object} The formatted message.
31+
*/
32+
function formatSlackMessage (query, response) {
33+
var entity;
34+
35+
// Extract the first entity from the result list, if any
36+
if (response && response.itemListElement &&
37+
response.itemListElement.length) {
38+
entity = response.itemListElement[0].result;
39+
}
40+
41+
// Prepare a rich Slack message
42+
// See https://api.slack.com/docs/message-formatting
43+
var slackMessage = {
44+
response_type: 'in_channel',
45+
text: 'Query: ' + query,
46+
attachments: []
47+
};
48+
49+
if (entity) {
50+
var attachment = {
51+
color: '#3367d6'
52+
};
53+
if (entity.name) {
54+
attachment.title = entity.name;
55+
if (entity.description) {
56+
attachment.title = attachment.title + ': ' + entity.description;
57+
}
58+
}
59+
if (entity.detailedDescription) {
60+
if (entity.detailedDescription.url) {
61+
attachment.title_link = entity.detailedDescription.url;
62+
}
63+
if (entity.detailedDescription.articleBody) {
64+
attachment.text = entity.detailedDescription.articleBody;
65+
}
66+
}
67+
if (entity.image && entity.image.contentUrl) {
68+
attachment.image_url = entity.image.contentUrl;
69+
}
70+
slackMessage.attachments.push(attachment);
71+
} else {
72+
slackMessage.attachments.push({
73+
text: 'No results match your query...'
74+
});
75+
}
76+
77+
return slackMessage;
78+
}
79+
// [END formatSlackMessage]
80+
81+
// [START verifyWebhook]
82+
/**
83+
* Verify that the webhook request came from Slack.
84+
*
85+
* @param {Object} body The body of the request.
86+
* @param {string} body.token The Slack token to be verified.
87+
*/
88+
function verifyWebhook (body) {
89+
if (!body || body.token !== config.SLACK_TOKEN) {
90+
var error = new Error('Invalid credentials');
91+
error.code = 401;
92+
throw error;
93+
}
94+
}
95+
// [END verifyWebhook]
96+
97+
// [START makeSearchRequest]
98+
/**
99+
* Send the user's search query to the Knowledge Graph API.
100+
*
101+
* @param {string} query The user's search query.
102+
* @param {Function} callback Callback function.
103+
*/
104+
function makeSearchRequest (query, callback) {
105+
kgsearch.entities.search({
106+
auth: config.KG_API_KEY,
107+
query: query,
108+
limit: 1
109+
}, function (err, response) {
110+
if (err) {
111+
return callback(err);
112+
}
113+
114+
// Return a formatted message
115+
return callback(null, formatSlackMessage(query, response));
116+
});
117+
}
118+
// [END makeSearchRequest]
119+
120+
// [START kgSearch]
121+
/**
122+
* Receive a Slash Command request from Slack.
123+
*
124+
* Trigger this function by making a POST request with a payload to:
125+
* https://[YOUR_REGION].[YOUR_PROJECT_ID].cloudfunctions.net/kgsearch
126+
*
127+
* @example
128+
* curl -X POST "https://us-central1.your-project-id.cloudfunctions.net/kgSearch" --data '{"token":"[YOUR_SLACK_TOKEN]","text":"giraffe"}'
129+
*
130+
* @param {Object} req Cloud Function request object.
131+
* @param {Object} req.body The request payload.
132+
* @param {string} req.body.token Slack's verification token.
133+
* @param {string} req.body.text The user's search query.
134+
* @param {Object} res Cloud Function response object.
135+
*/
136+
exports.kgSearch = function kgSearch (req, res) {
137+
try {
138+
if (req.method !== 'POST') {
139+
var error = new Error('Only POST requests are accepted');
140+
error.code = 405;
141+
throw error;
142+
}
143+
144+
// Verify that this request came from Slack
145+
verifyWebhook(req.body);
146+
147+
// Make the request to the Knowledge Graph Search API
148+
makeSearchRequest(req.body.text, function (err, response) {
149+
if (err) {
150+
console.error(err);
151+
return res.status(500);
152+
}
153+
154+
// Send the formatted message back to Slack
155+
return res.json(response);
156+
});
157+
} catch (err) {
158+
console.error(err);
159+
return res.status(err.code || 500).send(err.message);
160+
}
161+
};
162+
// [END kgSearch]

functions/slack/package.json

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "nodejs-docs-samples-functions-slack",
3+
"description": "Node.js samples found on https://cloud.google.com",
4+
"version": "0.0.1",
5+
"private": true,
6+
"license": "Apache Version 2.0",
7+
"author": "Google Inc.",
8+
"repository": {
9+
"type": "git",
10+
"url": "https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git"
11+
},
12+
"dependencies": {
13+
"googleapis": "^11.0.0"
14+
}
15+
}

0 commit comments

Comments
 (0)