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
This commit is contained in:
Michael Kochell 2021-04-02 14:04:31 -04:00 committed by GitHub
parent 777b35bda3
commit f766f47358
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 54 additions and 36 deletions

View file

@ -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:

View file

@ -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,

View file

@ -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<ActionResult>;
sendEphemeralPost: (message: any, channelId?: string, parentId?: string) => Promise<ActionResult>;
sendEphemeralPost: SendEphemeralPost;
};
post: Post;
binding: AppBinding;
@ -36,8 +37,6 @@ export default class ButtonBinding extends PureComponent<Props> {
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<Props> {
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(

View file

@ -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<ActionResult>;
sendEphemeralPost: (message: any, channelId?: string, parentId?: string) => Promise<ActionResult>;
sendEphemeralPost: SendEphemeralPost;
}
function mapDispatchToProps(dispatch: Dispatch<GenericAction>) {

View file

@ -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<ActionResult>;
sendEphemeralPost: (message: any, channelId?: string, parentId?: string) => Promise<ActionResult>;
sendEphemeralPost: SendEphemeralPost;
}
function mapDispatchToProps(dispatch: Dispatch<GenericAction>) {

View file

@ -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<ActionResult>;
sendEphemeralPost: (message: any, channelId?: string, parentId?: string) => Promise<ActionResult>;
sendEphemeralPost: SendEphemeralPost;
};
binding?: AppBinding;
post: Post;
@ -42,7 +43,6 @@ export default class MenuBinding extends PureComponent<Props, State> {
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<Props, State> {
);
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({

View file

@ -434,8 +434,7 @@ exports[`PostHeader should match snapshot when post isBot and shouldRenderReplyB
}
}
>
<TouchableWithFeedbackIOS
onPress={[Function]}
<View
style={
Array [
Object {
@ -448,7 +447,6 @@ exports[`PostHeader should match snapshot when post isBot and shouldRenderReplyB
},
]
}
type="opacity"
>
<Text
ellipsizeMode="tail"
@ -466,7 +464,7 @@ exports[`PostHeader should match snapshot when post isBot and shouldRenderReplyB
>
John Smith
</Text>
</TouchableWithFeedbackIOS>
</View>
<BotTag
style={
Object {
@ -589,8 +587,7 @@ exports[`PostHeader should match snapshot when post isBot and shouldRenderReplyB
}
}
>
<TouchableWithFeedbackIOS
onPress={[Function]}
<View
style={
Array [
Object {
@ -603,7 +600,6 @@ exports[`PostHeader should match snapshot when post isBot and shouldRenderReplyB
},
]
}
type="opacity"
>
<Text
ellipsizeMode="tail"
@ -621,7 +617,7 @@ exports[`PostHeader should match snapshot when post isBot and shouldRenderReplyB
>
John Smith
</Text>
</TouchableWithFeedbackIOS>
</View>
<BotTag
style={
Object {

View file

@ -142,6 +142,7 @@ export default class PostHeader extends PureComponent {
displayName,
enablePostUsernameOverride,
fromWebHook,
isBot,
isSystemMessage,
fromAutoResponder,
overrideUsername,
@ -153,7 +154,7 @@ export default class PostHeader extends PureComponent {
const displayNameWidth = this.calcNameWidth();
const displayNameStyle = [style.displayNameContainer, displayNameWidth];
if (fromAutoResponder || fromWebHook) {
if (fromAutoResponder || fromWebHook || isBot) {
let name = displayName;
if (overrideUsername && enablePostUsernameOverride) {
name = overrideUsername;

View file

@ -82,6 +82,12 @@ export type AppCallResponse<Res = unknown> = {
use_external_browser?: boolean;
call?: AppCall;
form?: AppForm;
app_metadata?: AppMetadataForClient;
};
export type AppMetadataForClient = {
bot_user_id: string;
bot_username: string;
};
export type AppContext = {

View file

@ -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<any>, error?: AppCallResponse<any>}>;
sendEphemeralPost: (message: any, channelId?: string, parentId?: string) => Promise<ActionResult>;
sendEphemeralPost: SendEphemeralPost;
};
theme: Theme;
componentId: string;
@ -81,7 +81,7 @@ export default class AppsFormContainer extends PureComponent<Props, State> {
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:

View file

@ -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<ActionResult>;
sendEphemeralPost: SendEphemeralPost;
};
function mapStateToProps(state: GlobalState) {

View file

@ -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<ActionResult>;
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<ActionResult>;
sendEphemeralPost: SendEphemeralPost;
},
}
@ -121,7 +121,7 @@ class Option extends React.PureComponent<OptionProps, OptionState> {
}
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) {

View file

@ -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<ActionResult>;
sendEphemeralPost: SendEphemeralPost;
}
function mapDispatchToProps(dispatch: Dispatch<GenericAction>) {

View file

@ -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<ActionResult>;
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<ActionResult>;
sendEphemeralPost: SendEphemeralPost;
},
}
@ -118,7 +118,7 @@ class Option extends React.PureComponent<OptionProps> {
}
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) {

View file

@ -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<ActionResult>;
sendEphemeralPost: SendEphemeralPost;
}
function mapDispatchToProps(dispatch: Dispatch<GenericAction>) {

8
types/actions/posts.d.ts vendored Normal file
View file

@ -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<ActionResult>;
}