From 3db8da75cb30d44faef56b65e35a8dcbbac63130 Mon Sep 17 00:00:00 2001 From: Kazuhiro Sera Date: Thu, 22 Apr 2021 07:05:04 +0900 Subject: [PATCH] Fix #534 respond support in view_submission listeners (it works only when response_url_enabled is true) (#889) --- src/App.spec.ts | 45 +++++++++++++++++++++++++++++++++++++++++ src/App.ts | 21 +++++++++++++------ src/types/view/index.ts | 3 ++- 3 files changed, 62 insertions(+), 7 deletions(-) diff --git a/src/App.spec.ts b/src/App.spec.ts index de2251045..b1179e8f2 100644 --- a/src/App.spec.ts +++ b/src/App.spec.ts @@ -1469,6 +1469,51 @@ describe('App', () => { ack: noop, }); + // Assert + assert.equal(fakeAxiosPost.callCount, 1); + // Assert that each call to fakeAxiosPost had the right arguments + assert(fakeAxiosPost.calledWith(responseUrl, responseObject)); + }); + it('should be able to use respond for view_submission payloads', async () => { + // Arrange + const responseObject = { text: 'response' }; + const responseUrl = 'https://fake.slack/response_url'; + const fakeAxiosPost = sinon.fake.resolves({}); + const overrides = buildOverrides([withNoopWebClient(), withAxiosPost(fakeAxiosPost)]); + const App = await importApp(overrides); // eslint-disable-line @typescript-eslint/naming-convention, no-underscore-dangle, id-blacklist, id-match + + // Act + const app = new App({ receiver: fakeReceiver, authorize: sinon.fake.resolves(dummyAuthorizationResult) }); + app.view('view-id', async ({ respond }) => { + await respond(responseObject); + }); + app.error(fakeErrorHandler); + await fakeReceiver.sendEvent({ + ack: noop, + body: { + type: 'view_submission', + team: {}, + user: {}, + view: { + id: 'V111', + type: 'modal', + callback_id: 'view-id', + state: {}, + title: {}, + close: {}, + submit: {}, + }, + response_urls: [ + { + block_id: 'b', + action_id: 'a', + channel_id: 'C111', + response_url: 'https://fake.slack/response_url', + }, + ], + }, + }); + // Assert assert.equal(fakeAxiosPost.callCount, 1); // Assert that each call to fakeAxiosPost had the right arguments diff --git a/src/App.ts b/src/App.ts index 05cb4946f..d9d6f9248 100644 --- a/src/App.ts +++ b/src/App.ts @@ -4,7 +4,7 @@ import { SecureContextOptions } from 'tls'; import util from 'util'; import { WebClient, ChatPostMessageArguments, addAppMetadata, WebClientOptions } from '@slack/web-api'; import { Logger, LogLevel, ConsoleLogger } from '@slack/logger'; -import axios, { AxiosInstance } from 'axios'; +import axios, { AxiosInstance, AxiosResponse } from 'axios'; import SocketModeReceiver from './receivers/SocketModeReceiver'; import HTTPReceiver, { HTTPReceiverOptions } from './receivers/HTTPReceiver'; import { @@ -765,11 +765,10 @@ export default class App { // Set respond() utility if (body.response_url) { - listenerArgs.respond = (response: string | RespondArguments): Promise => { - const validResponse: RespondArguments = typeof response === 'string' ? { text: response } : response; - - return this.axios.post(body.response_url, validResponse); - }; + listenerArgs.respond = buildRespondFn(this.axios, body.response_url); + } else if (typeof body.response_urls !== 'undefined' && body.response_urls.length > 0) { + // This can exist only when view_submission payloads - response_url_enabled: true + listenerArgs.respond = buildRespondFn(this.axios, body.response_urls[0].response_url); } // Set ack() utility @@ -1124,6 +1123,16 @@ function selectToken(context: Context): string | undefined { return context.botToken !== undefined ? context.botToken : context.userToken; } +function buildRespondFn( + axiosInstance: AxiosInstance, + response_url: string, +): (response: string | RespondArguments) => Promise { + return async (message: string | RespondArguments) => { + const normalizedArgs: RespondArguments = typeof message === 'string' ? { text: message } : message; + return axiosInstance.post(response_url, normalizedArgs); + }; +} + // ---------------------------- // For listener registration methods diff --git a/src/types/view/index.ts b/src/types/view/index.ts index 83f7d372c..17674199c 100644 --- a/src/types/view/index.ts +++ b/src/types/view/index.ts @@ -1,6 +1,6 @@ import { View, PlainTextElement } from '@slack/types'; import { StringIndexed } from '../helpers'; -import { AckFn } from '../utilities'; +import { AckFn, RespondFn } from '../utilities'; /** * Known view action types @@ -19,6 +19,7 @@ export interface SlackViewMiddlewareArgs; + respond: RespondFn; } interface PlainTextElementOutput {