From f766f4735850c1c9012e96cd225103101f3192f4 Mon Sep 17 00:00:00 2001 From: Michael Kochell <6913320+mickmister@users.noreply.github.com> Date: Fri, 2 Apr 2021 14:04:31 -0400 Subject: [PATCH] Post app call response ephemeral messages as bot (#5256) * post app call response ephemeral messages as bot * add check for isBot * add SendEphemeralPost func type * snapshot --- app/actions/views/command.ts | 2 +- app/actions/views/post.js | 4 ++-- .../button_binding/button_binding.tsx | 6 +++--- .../embedded_bindings/button_binding/index.ts | 3 ++- .../embedded_bindings/menu_binding/index.ts | 3 ++- .../embedded_bindings/menu_binding/menu_binding.tsx | 6 ++++-- .../__snapshots__/post_header.test.js.snap | 12 ++++-------- app/components/post_header/post_header.js | 3 ++- app/mm-redux/types/apps.ts | 6 ++++++ app/screens/apps_form/apps_form_container.tsx | 6 +++--- app/screens/apps_form/index.ts | 5 +++-- app/screens/channel_info/bindings/bindings.tsx | 8 ++++---- app/screens/channel_info/bindings/index.ts | 5 +++-- app/screens/post_options/bindings/bindings.tsx | 8 ++++---- app/screens/post_options/bindings/index.ts | 5 +++-- types/actions/posts.d.ts | 8 ++++++++ 16 files changed, 54 insertions(+), 36 deletions(-) create mode 100644 types/actions/posts.d.ts diff --git a/app/actions/views/command.ts b/app/actions/views/command.ts index 02cd10edd..96b380076 100644 --- a/app/actions/views/command.ts +++ b/app/actions/views/command.ts @@ -65,7 +65,7 @@ export function executeCommand(message: string, channelId: string, rootId: strin switch (callResp.type) { case AppCallResponseTypes.OK: if (callResp.markdown) { - dispatch(sendEphemeralPost(callResp.markdown, args.channel_id, args.parent_id)); + dispatch(sendEphemeralPost(callResp.markdown, args.channel_id, args.parent_id, callResp.app_metadata?.bot_user_id)); } return {data: {}}; case AppCallResponseTypes.FORM: diff --git a/app/actions/views/post.js b/app/actions/views/post.js index 2e684b7ef..009de775e 100644 --- a/app/actions/views/post.js +++ b/app/actions/views/post.js @@ -28,12 +28,12 @@ import {getChannelSinceValue} from '@utils/channels'; import {getEmojisInPosts} from './emoji'; -export function sendEphemeralPost(message, channelId = '', parentId = '') { +export function sendEphemeralPost(message, channelId = '', parentId = '', userId = '0') { return async (dispatch, getState) => { const timestamp = Date.now(); const post = { id: generateId(), - user_id: '0', + user_id: userId, channel_id: channelId || getCurrentChannelId(getState()), message, type: Posts.POST_TYPES.EPHEMERAL, diff --git a/app/components/embedded_bindings/button_binding/button_binding.tsx b/app/components/embedded_bindings/button_binding/button_binding.tsx index 86cd6f509..0ffa97c83 100644 --- a/app/components/embedded_bindings/button_binding/button_binding.tsx +++ b/app/components/embedded_bindings/button_binding/button_binding.tsx @@ -16,12 +16,13 @@ import {Post} from '@mm-redux/types/posts'; import {AppExpandLevels, AppBindingLocations, AppCallTypes, AppCallResponseTypes} from '@mm-redux/constants/apps'; import {createCallContext, createCallRequest} from '@utils/apps'; import {Channel} from '@mm-redux/types/channels'; +import {SendEphemeralPost} from 'types/actions/posts'; type Props = { actions: { doAppCall: (call: AppCallRequest, type: AppCallType, intl: any) => Promise<{data?: AppCallResponse, error?: AppCallResponse}>; getChannel: (channelId: string) => Promise; - sendEphemeralPost: (message: any, channelId?: string, parentId?: string) => Promise; + sendEphemeralPost: SendEphemeralPost; }; post: Post; binding: AppBinding; @@ -36,8 +37,6 @@ export default class ButtonBinding extends PureComponent { private mounted = false; handleActionPress = preventDoubleTap(async () => { - const ephemeral = (message: string) => this.props.actions.sendEphemeralPost(message, this.props.post.channel_id, this.props.post.root_id); - const { binding, post, @@ -73,6 +72,7 @@ export default class ButtonBinding extends PureComponent { this.setState({executing: false}); } + const ephemeral = (message: string) => this.props.actions.sendEphemeralPost(message, this.props.post.channel_id, this.props.post.root_id, res.data?.app_metadata?.bot_user_id); if (res.error) { const errorResponse = res.error; const errorMessage = errorResponse.error || intl.formatMessage( diff --git a/app/components/embedded_bindings/button_binding/index.ts b/app/components/embedded_bindings/button_binding/index.ts index 3bda0affe..456ea20fa 100644 --- a/app/components/embedded_bindings/button_binding/index.ts +++ b/app/components/embedded_bindings/button_binding/index.ts @@ -16,6 +16,7 @@ import ButtonBinding from './button_binding'; import {getChannel} from '@mm-redux/actions/channels'; import {sendEphemeralPost} from '@actions/views/post'; import {getCurrentTeamId} from '@mm-redux/selectors/entities/teams'; +import {SendEphemeralPost} from 'types/actions/posts'; type OwnProps = { postId: string; @@ -32,7 +33,7 @@ function mapStateToProps(state: GlobalState, ownProps: OwnProps) { type Actions = { doAppCall: (call: AppCallRequest, type: AppCallType, intl: any) => Promise<{data?: AppCallResponse, error?: AppCallResponse}>; getChannel: (channelId: string) => Promise; - sendEphemeralPost: (message: any, channelId?: string, parentId?: string) => Promise; + sendEphemeralPost: SendEphemeralPost; } function mapDispatchToProps(dispatch: Dispatch) { diff --git a/app/components/embedded_bindings/menu_binding/index.ts b/app/components/embedded_bindings/menu_binding/index.ts index 58d683901..25e0dddb7 100644 --- a/app/components/embedded_bindings/menu_binding/index.ts +++ b/app/components/embedded_bindings/menu_binding/index.ts @@ -8,6 +8,7 @@ import {GlobalState} from '@mm-redux/types/store'; import {doAppCall} from '@actions/apps'; import {ActionFunc, ActionResult, GenericAction} from '@mm-redux/types/actions'; import {AppCallRequest, AppCallResponse, AppCallType} from '@mm-redux/types/apps'; +import {SendEphemeralPost} from 'types/actions/posts'; import {getPost} from '@mm-redux/selectors/entities/posts'; import MenuBinding from './menu_binding'; @@ -29,7 +30,7 @@ function mapStateToProps(state: GlobalState, ownProps: OwnProps) { type Actions = { doAppCall: (call: AppCallRequest, type: AppCallType, intl: any) => Promise<{data?: AppCallResponse, error?: AppCallResponse}>; getChannel: (channelId: string) => Promise; - sendEphemeralPost: (message: any, channelId?: string, parentId?: string) => Promise; + sendEphemeralPost: SendEphemeralPost; } function mapDispatchToProps(dispatch: Dispatch) { diff --git a/app/components/embedded_bindings/menu_binding/menu_binding.tsx b/app/components/embedded_bindings/menu_binding/menu_binding.tsx index 1d0394385..e5830446b 100644 --- a/app/components/embedded_bindings/menu_binding/menu_binding.tsx +++ b/app/components/embedded_bindings/menu_binding/menu_binding.tsx @@ -12,12 +12,13 @@ import {ActionResult} from '@mm-redux/types/actions'; import {AppExpandLevels, AppBindingLocations, AppCallTypes, AppCallResponseTypes} from '@mm-redux/constants/apps'; import {Channel} from '@mm-redux/types/channels'; import {createCallContext, createCallRequest} from '@utils/apps'; +import {SendEphemeralPost} from 'types/actions/posts'; type Props = { actions: { doAppCall: (call: AppCallRequest, type: AppCallType, intl: any) => Promise<{data?: AppCallResponse, error?: AppCallResponse}>; getChannel: (channelId: string) => Promise; - sendEphemeralPost: (message: any, channelId?: string, parentId?: string) => Promise; + sendEphemeralPost: SendEphemeralPost; }; binding?: AppBinding; post: Post; @@ -42,7 +43,6 @@ export default class MenuBinding extends PureComponent { if (!selected) { return; } - const ephemeral = (message: string) => this.props.actions.sendEphemeralPost(message, this.props.post.channel_id, this.props.post.root_id); this.setState({selected}); const binding = this.props.binding?.bindings?.find((b) => b.location === selected.value); @@ -83,6 +83,8 @@ export default class MenuBinding extends PureComponent { ); const res = await actions.doAppCall(call, AppCallTypes.SUBMIT, this.context.intl); + + const ephemeral = (message: string) => this.props.actions.sendEphemeralPost(message, this.props.post.channel_id, this.props.post.root_id, res.data?.app_metadata?.bot_user_id); if (res.error) { const errorResponse = res.error; const errorMessage = errorResponse.error || intl.formatMessage({ diff --git a/app/components/post_header/__snapshots__/post_header.test.js.snap b/app/components/post_header/__snapshots__/post_header.test.js.snap index 37ee31856..d12909a61 100644 --- a/app/components/post_header/__snapshots__/post_header.test.js.snap +++ b/app/components/post_header/__snapshots__/post_header.test.js.snap @@ -434,8 +434,7 @@ exports[`PostHeader should match snapshot when post isBot and shouldRenderReplyB } } > - John Smith - + - John Smith - + = { use_external_browser?: boolean; call?: AppCall; form?: AppForm; + app_metadata?: AppMetadataForClient; +}; + +export type AppMetadataForClient = { + bot_user_id: string; + bot_username: string; }; export type AppContext = { diff --git a/app/screens/apps_form/apps_form_container.tsx b/app/screens/apps_form/apps_form_container.tsx index 4da480613..50970f1f5 100644 --- a/app/screens/apps_form/apps_form_container.tsx +++ b/app/screens/apps_form/apps_form_container.tsx @@ -9,14 +9,14 @@ import {AppCallResponse, AppCallRequest, AppField, AppForm, AppFormValues, FormR import {AppCallResponseTypes, AppCallTypes} from '@mm-redux/constants/apps'; import AppsFormComponent from './apps_form_component'; import {makeCallErrorResponse} from '@utils/apps'; -import {ActionResult} from '@mm-redux/types/actions'; +import {SendEphemeralPost} from 'types/actions/posts'; export type Props = { form?: AppForm; call?: AppCallRequest; actions: { doAppCall: (call: AppCallRequest, type: AppCallType, intl: any) => Promise<{data?: AppCallResponse, error?: AppCallResponse}>; - sendEphemeralPost: (message: any, channelId?: string, parentId?: string) => Promise; + sendEphemeralPost: SendEphemeralPost; }; theme: Theme; componentId: string; @@ -81,7 +81,7 @@ export default class AppsFormContainer extends PureComponent { switch (callResp.type) { case AppCallResponseTypes.OK: if (callResp.markdown) { - this.props.actions.sendEphemeralPost(callResp.markdown, call.context.channel_id, call.context.root_id || call.context.post_id); + this.props.actions.sendEphemeralPost(callResp.markdown, call.context.channel_id, call.context.root_id || call.context.post_id, callResp.app_metadata?.bot_user_id); } break; case AppCallResponseTypes.FORM: diff --git a/app/screens/apps_form/index.ts b/app/screens/apps_form/index.ts index d9ee80ef3..0e2685cee 100644 --- a/app/screens/apps_form/index.ts +++ b/app/screens/apps_form/index.ts @@ -9,14 +9,15 @@ import {doAppCall} from '@actions/apps'; import {AppCallResponse, AppCallRequest, AppCallType} from '@mm-redux/types/apps'; import {GlobalState} from '@mm-redux/types/store'; -import {ActionFunc, ActionResult, GenericAction} from '@mm-redux/types/actions'; +import {ActionFunc, GenericAction} from '@mm-redux/types/actions'; +import {SendEphemeralPost} from 'types/actions/posts'; import AppsFormContainer from './apps_form_container'; import {sendEphemeralPost} from '@actions/views/post'; type Actions = { doAppCall: (call: AppCallRequest, type: AppCallType, intl: any) => Promise<{data?: AppCallResponse, error?: AppCallResponse}>; - sendEphemeralPost: (message: any, channelId?: string, parentId?: string) => Promise; + sendEphemeralPost: SendEphemeralPost; }; function mapStateToProps(state: GlobalState) { diff --git a/app/screens/channel_info/bindings/bindings.tsx b/app/screens/channel_info/bindings/bindings.tsx index de784bff8..f77c97b6b 100644 --- a/app/screens/channel_info/bindings/bindings.tsx +++ b/app/screens/channel_info/bindings/bindings.tsx @@ -13,8 +13,8 @@ import {Theme} from '@mm-redux/types/preferences'; import {Channel} from '@mm-redux/types/channels'; import {AppCallResponseTypes, AppCallTypes} from '@mm-redux/constants/apps'; import {dismissModal} from '@actions/navigation'; -import {ActionResult} from '@mm-redux/types/actions'; import {createCallContext, createCallRequest} from '@utils/apps'; +import {SendEphemeralPost} from 'types/actions/posts'; type Props = { bindings: AppBinding[]; @@ -25,7 +25,7 @@ type Props = { currentTeamId: string; actions: { doAppCall: (call: AppCallRequest, type: AppCallType, intl: any) => Promise<{data?: AppCallResponse, error?: AppCallResponse}>; - sendEphemeralPost: (message: any, channelId?: string, parentId?: string) => Promise; + sendEphemeralPost: SendEphemeralPost; } } @@ -64,7 +64,7 @@ type OptionProps = { currentTeamId: string; actions: { doAppCall: (call: AppCallRequest, type: AppCallType, intl: any) => Promise<{data?: AppCallResponse, error?: AppCallResponse}>; - sendEphemeralPost: (message: any, channelId?: string, parentId?: string) => Promise; + sendEphemeralPost: SendEphemeralPost; }, } @@ -121,7 +121,7 @@ class Option extends React.PureComponent { } const callResp = res.data!; - const ephemeral = (message: string) => sendEphemeralPost(message, currentChannel.id); + const ephemeral = (message: string) => sendEphemeralPost(message, currentChannel.id, '', callResp.app_metadata?.bot_user_id); switch (callResp.type) { case AppCallResponseTypes.OK: if (callResp.markdown) { diff --git a/app/screens/channel_info/bindings/index.ts b/app/screens/channel_info/bindings/index.ts index 7f4668f3d..c34ecaf74 100644 --- a/app/screens/channel_info/bindings/index.ts +++ b/app/screens/channel_info/bindings/index.ts @@ -8,7 +8,7 @@ import {getAppsBindings} from '@mm-redux/selectors/entities/apps'; import {AppBindingLocations} from '@mm-redux/constants/apps'; import {getCurrentChannel} from '@mm-redux/selectors/entities/channels'; import {GlobalState} from '@mm-redux/types/store'; -import {ActionResult, GenericAction, ActionFunc} from '@mm-redux/types/actions'; +import {GenericAction, ActionFunc} from '@mm-redux/types/actions'; import {AppCallRequest, AppCallResponse, AppCallType} from '@mm-redux/types/apps'; import {appsEnabled} from '@utils/apps'; @@ -17,6 +17,7 @@ import {doAppCall} from '@actions/apps'; import Bindings from './bindings'; import {sendEphemeralPost} from '@actions/views/post'; import {getCurrentTeamId} from '@mm-redux/selectors/entities/teams'; +import {SendEphemeralPost} from 'types/actions/posts'; function mapStateToProps(state: GlobalState) { const apps = appsEnabled(state); @@ -33,7 +34,7 @@ function mapStateToProps(state: GlobalState) { type Actions = { doAppCall: (call: AppCallRequest, type: AppCallType, intl: any) => Promise<{data?: AppCallResponse, error?: AppCallResponse}>; - sendEphemeralPost: (message: any, channelId?: string, parentId?: string) => Promise; + sendEphemeralPost: SendEphemeralPost; } function mapDispatchToProps(dispatch: Dispatch) { diff --git a/app/screens/post_options/bindings/bindings.tsx b/app/screens/post_options/bindings/bindings.tsx index 6bb9f1fe1..4e94832f2 100644 --- a/app/screens/post_options/bindings/bindings.tsx +++ b/app/screens/post_options/bindings/bindings.tsx @@ -13,8 +13,8 @@ import {Theme} from '@mm-redux/types/preferences'; import {Post} from '@mm-redux/types/posts'; import {UserProfile} from '@mm-redux/types/users'; import {AppCallResponseTypes, AppCallTypes, AppExpandLevels} from '@mm-redux/constants/apps'; -import {ActionResult} from '@mm-redux/types/actions'; import {createCallContext, createCallRequest} from '@utils/apps'; +import {SendEphemeralPost} from 'types/actions/posts'; type Props = { bindings: AppBinding[], @@ -27,7 +27,7 @@ type Props = { intl: typeof intlShape, actions: { doAppCall: (call: AppCallRequest, type: AppCallType, intl: any) => Promise<{data?: AppCallResponse, error?: AppCallResponse}>; - sendEphemeralPost: (message: any, channelId?: string, parentId?: string) => Promise; + sendEphemeralPost: SendEphemeralPost; } } @@ -73,7 +73,7 @@ type OptionProps = { intl: typeof intlShape, actions: { doAppCall: (call: AppCallRequest, type: AppCallType, intl: any) => Promise<{data?: AppCallResponse, error?: AppCallResponse}>; - sendEphemeralPost: (message: any, channelId?: string, parentId?: string) => Promise; + sendEphemeralPost: SendEphemeralPost; }, } @@ -118,7 +118,7 @@ class Option extends React.PureComponent { } const callResp = (res as {data: AppCallResponse}).data; - const ephemeral = (message: string) => sendEphemeralPost(message, post.channel_id, post.root_id || post.id); + const ephemeral = (message: string) => sendEphemeralPost(message, post.channel_id, post.root_id || post.id, callResp.app_metadata?.bot_user_id); switch (callResp.type) { case AppCallResponseTypes.OK: if (callResp.markdown) { diff --git a/app/screens/post_options/bindings/index.ts b/app/screens/post_options/bindings/index.ts index fcaff19eb..0a91bd3af 100644 --- a/app/screens/post_options/bindings/index.ts +++ b/app/screens/post_options/bindings/index.ts @@ -8,7 +8,7 @@ import {getTheme} from '@mm-redux/selectors/entities/preferences'; import {GlobalState} from '@mm-redux/types/store'; import {AppCallRequest, AppCallResponse, AppCallType} from '@mm-redux/types/apps'; -import {ActionResult, GenericAction, ActionFunc} from '@mm-redux/types/actions'; +import {GenericAction, ActionFunc} from '@mm-redux/types/actions'; import {getAppsBindings} from '@mm-redux/selectors/entities/apps'; import {AppBindingLocations} from '@mm-redux/constants/apps'; import {getCurrentUser} from '@mm-redux/selectors/entities/users'; @@ -21,6 +21,7 @@ import {getCurrentTeamId} from '@mm-redux/selectors/entities/teams'; import {sendEphemeralPost} from '@actions/views/post'; import {Post} from '@mm-redux/types/posts'; import {getChannel} from '@mm-redux/selectors/entities/channels'; +import {SendEphemeralPost} from 'types/actions/posts'; type OwnProps = { post: Post; @@ -43,7 +44,7 @@ function mapStateToProps(state: GlobalState, props: OwnProps) { type Actions = { doAppCall: (call: AppCallRequest, type: AppCallType, intl: any) => Promise<{data?: AppCallResponse, error?: AppCallResponse}>; - sendEphemeralPost: (message: any, channelId?: string, parentId?: string) => Promise; + sendEphemeralPost: SendEphemeralPost; } function mapDispatchToProps(dispatch: Dispatch) { diff --git a/types/actions/posts.d.ts b/types/actions/posts.d.ts new file mode 100644 index 000000000..8b5adcea6 --- /dev/null +++ b/types/actions/posts.d.ts @@ -0,0 +1,8 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {ActionResult} from '@mm-redux/types/actions'; + +export interface SendEphemeralPost { + (message: string, channelId?: string, parentId?: string, userId?: string): Promise; +}