Skip to content

Commit

Permalink
port: save conversation state before sending card (#3635) (#3640)
Browse files Browse the repository at this point in the history
Fixes #3634

Co-authored-by: Steven Gum <14935595+stevengum@users.noreply.github.com>

Co-authored-by: Steven Gum <14935595+stevengum@users.noreply.github.com>
  • Loading branch information
joshgummersall and stevengum authored Apr 28, 2021
1 parent 4199f06 commit ebfa19e
Showing 1 changed file with 31 additions and 11 deletions.
42 changes: 31 additions & 11 deletions libraries/botbuilder-dialogs-adaptive/src/input/oauthInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,24 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { InputDialog, InputDialogConfiguration, InputState } from './inputDialog';
import { TextTemplate } from '../templates';

import {
ConversationState,
tokenExchangeOperationName,
tokenResponseEventName,
verifyStateOperationName,
} from 'botbuilder';

import {
Expression,
IntExpression,
IntExpressionConverter,
StringExpression,
StringExpressionConverter,
} from 'adaptive-expressions';

import {
Activity,
ActivityTypes,
Expand All @@ -23,6 +34,7 @@ import {
TokenResponse,
TurnContext,
} from 'botbuilder';

import {
Converter,
ConverterFactory,
Expand All @@ -37,9 +49,6 @@ import {
ThisPath,
TurnPath,
} from 'botbuilder-dialogs';
import { verifyStateOperationName, tokenExchangeOperationName, tokenResponseEventName } from 'botbuilder';
import { InputDialog, InputDialogConfiguration, InputState } from './inputDialog';
import { TextTemplate } from '../templates';

export const channels: any = {
console: 'console',
Expand Down Expand Up @@ -326,9 +335,6 @@ export class OAuthInput extends InputDialog implements OAuthInputConfiguration {
return adapter.signOutUser(dc.context, this.connectionName.getValue(dc.state));
}

/**
* @protected
*/
protected onComputeId(): string {
return `OAuthInput[${this.prompt && this.prompt.toString()}]`;
}
Expand All @@ -343,27 +349,41 @@ export class OAuthInput extends InputDialog implements OAuthInputConfiguration {
throw new Error('Method not implemented.');
}

/**
* @private
*/
private async sendOAuthCard(dc: DialogContext, prompt?: string | Partial<Activity>): Promise<void> {
let title: string =
// Save state prior to sending OAuthCard: the invoke response for a token exchange from the root bot could come
// in before this method ends or could land in another instance in scale-out scenarios, which means that if the
// state is not saved, the OAuthInput would not be at the top of the stack, and the token exchange invoke would
// get discarded.
const conversationState = dc.context.turnState.get<ConversationState>('ConversationState');
if (conversationState) {
await conversationState.saveChanges(dc.context, false);
}

// Prepare oauth card
let title =
(await new TextTemplate<DialogStateManager>(this.title.expressionText).bind(dc, dc.state)) ??
this.title.getValue(dc.state);

if (title?.startsWith('=')) {
title = Expression.parse(title).tryEvaluate(dc.state)?.value;
}
let text: string =

let text =
(await new TextTemplate<DialogStateManager>(this.text.expressionText).bind(dc, dc.state)) ??
this.text.getValue(dc.state);

if (text?.startsWith('=')) {
text = Expression.parse(text).tryEvaluate(dc.state)?.value;
}

const settings: OAuthPromptSettings = {
connectionName: this.connectionName?.getValue(dc.state),
title,
text,
};

// Send OAuthCard to root bot. The root bot could attempt to do a token exchange or if it cannot do token
// exchange for this connection it will let the card get to the user to allow them to sign in.
return OAuthPrompt.sendOAuthCard(settings, dc.context, prompt);
}

Expand Down

0 comments on commit ebfa19e

Please sign in to comment.