diff --git a/functions/gcs/test/index.test.js b/functions/gcs/test/index.test.js index c138901cd69..c0397e5ea94 100644 --- a/functions/gcs/test/index.test.js +++ b/functions/gcs/test/index.test.js @@ -66,6 +66,23 @@ describe(`functions:gcs`, () => { ); }); + it(`Does nothing for deleted files`, (done) => { + const event = { + data: { + resourceState: `not_exists` + } + }; + const sample = getSample(); + + sample.program.wordCount(event, (err, message) => { + assert.ifError(err); + assert.equal(message, undefined); + assert.deepEqual(sample.mocks.storage.bucket.callCount, 0); + assert.deepEqual(sample.mocks.bucket.file.callCount, 0); + done(); + }); + }); + it(`Reads the file line by line`, (done) => { const expectedMsg = `File ${filename} has 114 words`; const event = { diff --git a/functions/ocr/app/index.js b/functions/ocr/app/index.js index 475804fdea2..ed52e9ec7d5 100644 --- a/functions/ocr/app/index.js +++ b/functions/ocr/app/index.js @@ -1,15 +1,17 @@ -// Copyright 2016, Google, Inc. -// 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. +/** + * Copyright 2016, Google, Inc. + * 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. + */ 'use strict'; @@ -37,9 +39,7 @@ const translate = require('@google-cloud/translate')({ */ function publishResult (topicName, data) { return pubsub.topic(topicName).get({ autoCreate: true }) - .then(([topic]) => { - return topic.publish({ data }) - }); + .then(([topic]) => topic.publish({ data })); } // [END functions_ocr_publish] diff --git a/functions/ocr/app/test/index.test.js b/functions/ocr/app/test/index.test.js index 247dd5c5343..adf7f1c22d3 100644 --- a/functions/ocr/app/test/index.test.js +++ b/functions/ocr/app/test/index.test.js @@ -1,15 +1,17 @@ -// Copyright 2016, Google, Inc. -// 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. +/** + * Copyright 2016, Google, Inc. + * 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. + */ 'use strict'; diff --git a/functions/sendgrid/index.js b/functions/sendgrid/index.js index 3052071d487..3bd1051ac07 100644 --- a/functions/sendgrid/index.js +++ b/functions/sendgrid/index.js @@ -1,29 +1,29 @@ -// Copyright 2016, Google, Inc. -// 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. +/** + * Copyright 2016, Google, Inc. + * 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. + */ 'use strict'; // [START functions_sendgrid_setup] -var async = require('async'); -var sendgrid = require('sendgrid'); -var config = require('./config.json'); -var gcloud = require('google-cloud'); -var uuid = require('node-uuid'); +const sendgrid = require('sendgrid'); +const config = require('./config.json'); +const uuid = require('node-uuid'); // Get a reference to the Cloud Storage component -var storage = gcloud.storage(); +const storage = require('@google-cloud/storage')(); // Get a reference to the BigQuery component -var bigquery = gcloud.bigquery(); +const bigquery = require('@google-cloud/bigquery')(); // [END functions_sendgrid_setup] // [START functions_sendgrid_get_client] @@ -31,18 +31,17 @@ var bigquery = gcloud.bigquery(); * Returns a configured SendGrid client. * * @param {string} key Your SendGrid API key. - * @returns {Object} SendGrid client. + * @returns {object} SendGrid client. */ function getClient (key) { if (!key) { - var error = new Error('SendGrid API key not provided. Make sure you have a ' + - '"sg_key" property in your request querystring'); + const error = new Error('SendGrid API key not provided. Make sure you have a "sg_key" property in your request querystring'); error.code = 401; throw error; } // Using SendGrid's Node.js Library https://github.com/sendgrid/sendgrid-nodejs - return sendgrid.SendGrid(key); + return sendgrid(key); } // [END functions_sendgrid_get_client] @@ -50,48 +49,53 @@ function getClient (key) { /** * Constructs the SendGrid email request from the HTTP request body. * - * @param {Object} requestBody Cloud Function request body. + * @param {object} requestBody Cloud Function request body. * @param {string} data.to Email address of the recipient. * @param {string} data.from Email address of the sender. * @param {string} data.subject Email subject line. * @param {string} data.body Body of the email subject line. - * @returns {Object} Payload object. + * @returns {object} Payload object. */ function getPayload (requestBody) { if (!requestBody.to) { - var error = new Error('To email address not provided. Make sure you have a ' + - '"to" property in your request'); + const error = new Error('To email address not provided. Make sure you have a "to" property in your request'); error.code = 400; throw error; - } - - if (!requestBody.from) { - error = new Error('From email address not provided. Make sure you have a ' + - '"from" property in your request'); + } else if (!requestBody.from) { + const error = new Error('From email address not provided. Make sure you have a "from" property in your request'); error.code = 400; throw error; - } - - if (!requestBody.subject) { - error = new Error('Email subject line not provided. Make sure you have a ' + - '"subject" property in your request'); + } else if (!requestBody.subject) { + const error = new Error('Email subject line not provided. Make sure you have a "subject" property in your request'); error.code = 400; throw error; - } - - if (!requestBody.body) { - error = new Error('Email content not provided. Make sure you have a ' + - '"body" property in your request'); + } else if (!requestBody.body) { + const error = new Error('Email content not provided. Make sure you have a "body" property in your request'); error.code = 400; throw error; } - return new sendgrid.mail.Mail( - new sendgrid.mail.Email(requestBody.from), - requestBody.subject, - new sendgrid.mail.Email(requestBody.to), - new sendgrid.mail.Content('text/plain', requestBody.body) - ); + return { + personalizations: [ + { + to: [ + { + email: requestBody.to + } + ], + subject: requestBody.subject + } + ], + from: { + email: requestBody.from + }, + content: [ + { + type: 'text/plain', + value: requestBody.body + } + ] + }; } // [END functions_get_payload] @@ -105,42 +109,48 @@ function getPayload (requestBody) { * @example * curl -X POST "https://us-central1.your-project-id.cloudfunctions.net/sendEmail?sg_key=your_api_key" --data '{"to":"bob@email.com","from":"alice@email.com","subject":"Hello from Sendgrid!","body":"Hello World!"}' --header "Content-Type: application/json" * - * @param {Object} req Cloud Function request context. - * @param {Object} req.query The parsed querystring. + * @param {object} req Cloud Function request context. + * @param {object} req.query The parsed querystring. * @param {string} req.query.sg_key Your SendGrid API key. - * @param {Object} req.body The request payload. + * @param {object} req.body The request payload. * @param {string} req.body.to Email address of the recipient. * @param {string} req.body.from Email address of the sender. * @param {string} req.body.subject Email subject line. * @param {string} req.body.body Body of the email subject line. - * @param {Object} res Cloud Function response context. + * @param {object} res Cloud Function response context. */ exports.sendgridEmail = function sendgridEmail (req, res) { - try { - if (req.method !== 'POST') { - var error = new Error('Only POST requests are accepted'); - error.code = 405; - throw error; - } + return Promise.resolve() + .then(() => { + if (req.method !== 'POST') { + const error = new Error('Only POST requests are accepted'); + error.code = 405; + throw error; + } - // Get a SendGrid client - var client = getClient(req.query.sg_key); + // Get a SendGrid client + const client = getClient(req.query.sg_key); - // Build the SendGrid request to send email - var request = client.emptyRequest(); - request.method = 'POST'; - request.path = '/v3/mail/send'; - request.body = getPayload(req.body).toJSON(); + // Build the SendGrid request to send email + const request = client.emptyRequest({ + method: 'POST', + path: '/v3/mail/send', + body: getPayload(req.body) + }); - // Make the request to SendGrid's API - console.log('Sending email to: ' + req.body.to); - client.API(request, function (response) { + // Make the request to SendGrid's API + console.log(`Sending email to: ${req.body.to}`); + return client.API(request); + }) + .then((response) => { if (response.statusCode < 200 || response.statusCode >= 400) { - console.error(response); - } else { - console.log('Email sent to: ' + req.body.to); + const error = Error(response.body); + error.code = response.statusCode; + throw error; } + console.log(`Email sent to: ${req.body.to}`); + // Forward the response back to the requester res.status(response.statusCode); if (response.headers['content-type']) { @@ -154,11 +164,12 @@ exports.sendgridEmail = function sendgridEmail (req, res) { } else { res.end(); } + }) + .catch((err) => { + console.error(err); + const code = err.code || (err.response ? err.response.statusCode : 500) || 500; + res.status(code).send(err); }); - } catch (err) { - console.error(err); - return res.status(err.code || 500).send(err.message); - } }; // [END functions_sendgrid_email] @@ -169,10 +180,10 @@ exports.sendgridEmail = function sendgridEmail (req, res) { * @param {string} authorization The authorization header of the request, e.g. "Basic ZmdvOhJhcg==" */ function verifyWebhook (authorization) { - var basicAuth = new Buffer(authorization.replace('Basic ', ''), 'base64').toString(); - var parts = basicAuth.split(':'); + const basicAuth = new Buffer(authorization.replace('Basic ', ''), 'base64').toString(); + const parts = basicAuth.split(':'); if (parts[0] !== config.USERNAME || parts[1] !== config.PASSWORD) { - var error = new Error('Invalid credentials'); + const error = new Error('Invalid credentials'); error.code = 401; throw error; } @@ -189,17 +200,15 @@ function fixNames (obj) { if (Array.isArray(obj)) { obj.forEach(fixNames); } else if (obj && typeof obj === 'object') { - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - var value = obj[key]; - fixNames(value); - var fixedKey = key.replace('-', '_'); - if (fixedKey !== key) { - obj[fixedKey] = value; - delete obj[key]; - } + Object.keys(obj).forEach((key) => { + const value = obj[key]; + fixNames(value); + const fixedKey = key.replace('-', '_'); + if (fixedKey !== key) { + obj[fixedKey] = value; + delete obj[key]; } - } + }); } } // [END functions_sendgrid_fix_names] @@ -210,54 +219,48 @@ function fixNames (obj) { * * See https://sendgrid.com/docs/API_Reference/Webhooks/event.html * - * @param {Object} req Cloud Function request context. - * @param {Object} res Cloud Function response context. + * @param {object} req Cloud Function request context. + * @param {object} res Cloud Function response context. */ exports.sendgridWebhook = function sendgridWebhook (req, res) { - try { - if (req.method !== 'POST') { - var error = new Error('Only POST requests are accepted'); - error.code = 405; - throw error; - } - - verifyWebhook(req.get('authorization') || ''); + return Promise.resolve() + .then(() => { + if (req.method !== 'POST') { + const error = new Error('Only POST requests are accepted'); + error.code = 405; + throw error; + } - var events = req.body || []; + verifyWebhook(req.get('authorization') || ''); - // Make sure property names in the data meet BigQuery standards - fixNames(events); + const events = req.body || []; - // Generate newline-delimited JSON - // See https://cloud.google.com/bigquery/data-formats#json_format - var json = events.map(function (event) { - return JSON.stringify(event); - }).join('\n'); + // Make sure property names in the data meet BigQuery standards + fixNames(events); - // Upload a new file to Cloud Storage if we have events to save - if (json.length) { - var bucketName = config.EVENT_BUCKET; - var unixTimestamp = new Date().getTime() * 1000; - var filename = '' + unixTimestamp + '-' + uuid.v4() + '.json'; - var file = storage.bucket(bucketName).file(filename); + // Generate newline-delimited JSON + // See https://cloud.google.com/bigquery/data-formats#json_format + const json = events.map((event) => JSON.stringify(event)).join('\n'); - console.log('Saving events to ' + filename + ' in bucket ' + bucketName); + // Upload a new file to Cloud Storage if we have events to save + if (json.length) { + const bucketName = config.EVENT_BUCKET; + const unixTimestamp = new Date().getTime() * 1000; + const filename = `${unixTimestamp}-${uuid.v4()}.json`; + const file = storage.bucket(bucketName).file(filename); - return file.save(json, function (err) { - if (err) { - console.error(err); - return res.status(500).end(); - } - console.log('JSON written to ' + filename); - return res.status(200).end(); - }); - } + console.log(`Saving events to ${filename} in bucket ${bucketName}`); - return res.status(200).end(); - } catch (err) { - console.error(err); - return res.status(err.code || 500).send(err.message); - } + return file.save(json).then(() => { + console.log(`JSON written to ${filename}`); + }); + } + }) + .then(() => res.status(200).end()) + .catch((err) => { + console.error(err); + res.status(err.code || 500).send(err); + }); }; // [END functions_sendgrid_webhook] @@ -265,27 +268,13 @@ exports.sendgridWebhook = function sendgridWebhook (req, res) { /** * Helper method to get a handle on a BigQuery table. Automatically creates the * dataset and table if necessary. - * - * @param {Function} callback Callback function. */ -function getTable (callback) { - var dataset = bigquery.dataset(config.DATASET); - return dataset.get({ - autoCreate: true - }, function (err, dataset) { - if (err) { - return callback(err); - } - var table = dataset.table(config.TABLE); - return table.get({ - autoCreate: true - }, function (err, table) { - if (err) { - return callback(err); - } - return callback(null, table); - }); - }); +function getTable () { + const dataset = bigquery.dataset(config.DATASET); + const options = { autoCreate: true }; + + return dataset.get(options) + .then(([dataset]) => dataset.table(config.TABLE).get(options)); } // [END functions_sendgrid_get_table] @@ -293,69 +282,47 @@ function getTable (callback) { /** * Cloud Function triggered by Cloud Storage when a file is uploaded. * - * @param {Object} context Cloud Function context. + * @param {object} context Cloud Function context. * @param {Function} context.success Success callback. * @param {Function} context.failure Failure callback. - * @param {Object} data Request data, in this case an object provided by Cloud Storage. + * @param {object} data Request data, in this case an object provided by Cloud Storage. * @param {string} data.bucket Name of the Cloud Storage bucket. * @param {string} data.name Name of the file. * @param {string} [data.timeDeleted] Time the file was deleted if this is a deletion event. * @see https://cloud.google.com/storage/docs/json_api/v1/objects#resource */ -exports.sendgridLoad = function sendgridLoad (context, data) { - try { - if (data.hasOwnProperty('timeDeleted')) { - // This was a deletion event, we don't want to process this - return context.done(); - } - - if (!data.bucket) { - throw new Error('Bucket not provided. Make sure you have a ' + - '"bucket" property in your request'); - } - if (!data.name) { - throw new Error('Filename not provided. Make sure you have a ' + - '"name" property in your request'); - } +exports.sendgridLoad = function sendgridLoad (event) { + const file = event.data; - return async.waterfall([ - // Get a handle on the table - function (callback) { - getTable(callback); - }, - // Start the load job - function (table, callback) { - console.log('Starting job for ' + data.name); + if (file.resourceState === 'not_exists') { + // This was a deletion event, we don't want to process this + return; + } - var file = storage.bucket(data.bucket).file(data.name); - var metadata = { - autodetect: true, - sourceFormat: 'NEWLINE_DELIMITED_JSON' - }; - table.import(file, metadata, callback); - }, - // Here we wait for the job to finish (or fail) in order to log the - // job result, but one could just exit without waiting. - function (job, apiResponse, callback) { - job.on('complete', function () { - console.log('Job complete for ' + data.name); - callback(); - }); - job.on('error', function (err) { - console.error('Job failed for ' + data.name); - callback(err); - }); - } - ], function (err) { - if (err) { - console.error(err); - return context.failure(err); + return Promise.resolve() + .then(() => { + if (!file.bucket) { + throw new Error('Bucket not provided. Make sure you have a "bucket" property in your request'); + } else if (!file.name) { + throw new Error('Filename not provided. Make sure you have a "name" property in your request'); } - return context.success(); + + return getTable(); + }) + .then(([table]) => { + const fileObj = storage.bucket(file.bucket).file(file.name); + console.log(`Starting job for ${file.name}`); + const metadata = { + autodetect: true, + sourceFormat: 'NEWLINE_DELIMITED_JSON' + }; + return table.import(fileObj, metadata); + }) + .then(([job]) => job.promise()) + .then(() => console.log(`Job complete for ${file.name}`)) + .catch((err) => { + console.log(`Job failed for ${file.name}`); + throw err; }); - } catch (err) { - console.error(err); - return context.failure(err.message); - } }; // [END functions_sendgrid_load] diff --git a/functions/sendgrid/package.json b/functions/sendgrid/package.json index da7fa806293..45a9f719bca 100644 --- a/functions/sendgrid/package.json +++ b/functions/sendgrid/package.json @@ -6,15 +6,15 @@ "author": "Google Inc.", "main": "./index.js", "scripts": { - "test": "mocha -R spec -t 120000 --require intelli-espower-loader ../../test/_setup.js test/*.test.js" + "test": "mocha -R spec -t 1000 --require intelli-espower-loader ../../test/_setup.js test/*.test.js" }, "dependencies": { - "async": "^2.0.1", - "google-cloud": "^0.38.3", + "@google-cloud/storage": "^0.4.0", + "@google-cloud/bigquery": "^0.4.0", "node-uuid": "^1.4.7", - "sendgrid": "^3.0.5" + "sendgrid": "^4.7.1" }, "devDependencies": { - "mocha": "^3.0.2" + "mocha": "^3.1.2" } } diff --git a/functions/slack/index.js b/functions/slack/index.js index e202e6973fa..b8473fb7d52 100644 --- a/functions/slack/index.js +++ b/functions/slack/index.js @@ -1,24 +1,26 @@ -// Copyright 2016, Google, Inc. -// 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. +/** + * Copyright 2016, Google, Inc. + * 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. + */ 'use strict'; // [START functions_slack_setup] -var config = require('./config.json'); -var googleapis = require('googleapis'); +const config = require('./config.json'); +const googleapis = require('googleapis'); // Get a reference to the Knowledge Graph Search component -var kgsearch = googleapis.kgsearch('v1'); +const kgsearch = googleapis.kgsearch('v1'); // [END functions_slack_setup] // [START functions_slack_format] @@ -26,34 +28,33 @@ var kgsearch = googleapis.kgsearch('v1'); * Format the Knowledge Graph API response into a richly formatted Slack message. * * @param {string} query The user's search query. - * @param {Object} response The response from the Knowledge Graph API. - * @returns {Object} The formatted message. + * @param {object} response The response from the Knowledge Graph API. + * @returns {object} The formatted message. */ function formatSlackMessage (query, response) { - var entity; + let entity; // Extract the first entity from the result list, if any - if (response && response.itemListElement && - response.itemListElement.length) { + if (response && response.itemListElement && response.itemListElement.length) { entity = response.itemListElement[0].result; } // Prepare a rich Slack message // See https://api.slack.com/docs/message-formatting - var slackMessage = { + const slackMessage = { response_type: 'in_channel', - text: 'Query: ' + query, + text: `Query: ${query}`, attachments: [] }; if (entity) { - var attachment = { + const attachment = { color: '#3367d6' }; if (entity.name) { attachment.title = entity.name; if (entity.description) { - attachment.title = attachment.title + ': ' + entity.description; + attachment.title = `${attachment.title}: ${entity.description}`; } } if (entity.detailedDescription) { @@ -82,12 +83,12 @@ function formatSlackMessage (query, response) { /** * Verify that the webhook request came from Slack. * - * @param {Object} body The body of the request. + * @param {object} body The body of the request. * @param {string} body.token The Slack token to be verified. */ function verifyWebhook (body) { if (!body || body.token !== config.SLACK_TOKEN) { - var error = new Error('Invalid credentials'); + const error = new Error('Invalid credentials'); error.code = 401; throw error; } @@ -99,20 +100,23 @@ function verifyWebhook (body) { * Send the user's search query to the Knowledge Graph API. * * @param {string} query The user's search query. - * @param {Function} callback Callback function. */ -function makeSearchRequest (query, callback) { - kgsearch.entities.search({ - auth: config.KG_API_KEY, - query: query, - limit: 1 - }, function (err, response) { - if (err) { - return callback(err); - } +function makeSearchRequest (query) { + return new Promise((resolve, reject) => { + kgsearch.entities.search({ + auth: config.KG_API_KEY, + query: query, + limit: 1 + }, (err, response) => { + console.log(err); + if (err) { + reject(err); + return; + } - // Return a formatted message - return callback(null, formatSlackMessage(query, response)); + // Return a formatted message + resolve(formatSlackMessage(query, response)); + }); }); } // [END functions_slack_request] @@ -127,36 +131,34 @@ function makeSearchRequest (query, callback) { * @example * curl -X POST "https://us-central1.your-project-id.cloudfunctions.net/kgSearch" --data '{"token":"[YOUR_SLACK_TOKEN]","text":"giraffe"}' * - * @param {Object} req Cloud Function request object. - * @param {Object} req.body The request payload. + * @param {object} req Cloud Function request object. + * @param {object} req.body The request payload. * @param {string} req.body.token Slack's verification token. * @param {string} req.body.text The user's search query. - * @param {Object} res Cloud Function response object. + * @param {object} res Cloud Function response object. */ exports.kgSearch = function kgSearch (req, res) { - try { - if (req.method !== 'POST') { - var error = new Error('Only POST requests are accepted'); - error.code = 405; - throw error; - } - - // Verify that this request came from Slack - verifyWebhook(req.body); - - // Make the request to the Knowledge Graph Search API - makeSearchRequest(req.body.text, function (err, response) { - if (err) { - console.error(err); - return res.status(500); + return Promise.resolve() + .then(() => { + if (req.method !== 'POST') { + const error = new Error('Only POST requests are accepted'); + error.code = 405; + throw error; } + // Verify that this request came from Slack + verifyWebhook(req.body); + + // Make the request to the Knowledge Graph Search API + return makeSearchRequest(req.body.text); + }) + .then((response) => { // Send the formatted message back to Slack - return res.json(response); + res.json(response); + }) + .catch((err) => { + console.error(err); + res.status(err.code || 500).send(err); }); - } catch (err) { - console.error(err); - return res.status(err.code || 500).send(err.message); - } }; // [END functions_slack_search] diff --git a/functions/slack/package.json b/functions/slack/package.json index 153814296da..455bec08fcb 100644 --- a/functions/slack/package.json +++ b/functions/slack/package.json @@ -6,12 +6,12 @@ "author": "Google Inc.", "main": "./index.js", "scripts": { - "test": "mocha -R spec -t 120000 --require intelli-espower-loader ../../test/_setup.js test/*.test.js" + "test": "mocha -R spec -t 1000 --require intelli-espower-loader ../../test/_setup.js test/*.test.js" }, "dependencies": { - "googleapis": "^12.0.0" + "googleapis": "^14.1.0" }, "devDependencies": { - "mocha": "^2.5.3" + "mocha": "^3.1.2" } }