5
5
* Copyright (c) Microsoft Corporation. All rights reserved.
6
6
* Licensed under the MIT License.
7
7
*/
8
+ import { InputDialog , InputDialogConfiguration , InputState } from './inputDialog' ;
9
+ import { TextTemplate } from '../templates' ;
10
+
11
+ import {
12
+ ConversationState ,
13
+ tokenExchangeOperationName ,
14
+ tokenResponseEventName ,
15
+ verifyStateOperationName ,
16
+ } from 'botbuilder' ;
17
+
8
18
import {
9
19
Expression ,
10
20
IntExpression ,
11
21
IntExpressionConverter ,
12
22
StringExpression ,
13
23
StringExpressionConverter ,
14
24
} from 'adaptive-expressions' ;
25
+
15
26
import {
16
27
Activity ,
17
28
ActivityTypes ,
@@ -23,6 +34,7 @@ import {
23
34
TokenResponse ,
24
35
TurnContext ,
25
36
} from 'botbuilder' ;
37
+
26
38
import {
27
39
Converter ,
28
40
ConverterFactory ,
@@ -37,9 +49,6 @@ import {
37
49
ThisPath ,
38
50
TurnPath ,
39
51
} from 'botbuilder-dialogs' ;
40
- import { verifyStateOperationName , tokenExchangeOperationName , tokenResponseEventName } from 'botbuilder' ;
41
- import { InputDialog , InputDialogConfiguration , InputState } from './inputDialog' ;
42
- import { TextTemplate } from '../templates' ;
43
52
44
53
export const channels : any = {
45
54
console : 'console' ,
@@ -326,9 +335,6 @@ export class OAuthInput extends InputDialog implements OAuthInputConfiguration {
326
335
return adapter . signOutUser ( dc . context , this . connectionName . getValue ( dc . state ) ) ;
327
336
}
328
337
329
- /**
330
- * @protected
331
- */
332
338
protected onComputeId ( ) : string {
333
339
return `OAuthInput[${ this . prompt && this . prompt . toString ( ) } ]` ;
334
340
}
@@ -343,27 +349,41 @@ export class OAuthInput extends InputDialog implements OAuthInputConfiguration {
343
349
throw new Error ( 'Method not implemented.' ) ;
344
350
}
345
351
346
- /**
347
- * @private
348
- */
349
352
private async sendOAuthCard ( dc : DialogContext , prompt ?: string | Partial < Activity > ) : Promise < void > {
350
- let title : string =
353
+ // Save state prior to sending OAuthCard: the invoke response for a token exchange from the root bot could come
354
+ // in before this method ends or could land in another instance in scale-out scenarios, which means that if the
355
+ // state is not saved, the OAuthInput would not be at the top of the stack, and the token exchange invoke would
356
+ // get discarded.
357
+ const conversationState = dc . context . turnState . get < ConversationState > ( 'ConversationState' ) ;
358
+ if ( conversationState ) {
359
+ await conversationState . saveChanges ( dc . context , false ) ;
360
+ }
361
+
362
+ // Prepare oauth card
363
+ let title =
351
364
( await new TextTemplate < DialogStateManager > ( this . title . expressionText ) . bind ( dc , dc . state ) ) ??
352
365
this . title . getValue ( dc . state ) ;
366
+
353
367
if ( title ?. startsWith ( '=' ) ) {
354
368
title = Expression . parse ( title ) . tryEvaluate ( dc . state ) ?. value ;
355
369
}
356
- let text : string =
370
+
371
+ let text =
357
372
( await new TextTemplate < DialogStateManager > ( this . text . expressionText ) . bind ( dc , dc . state ) ) ??
358
373
this . text . getValue ( dc . state ) ;
374
+
359
375
if ( text ?. startsWith ( '=' ) ) {
360
376
text = Expression . parse ( text ) . tryEvaluate ( dc . state ) ?. value ;
361
377
}
378
+
362
379
const settings : OAuthPromptSettings = {
363
380
connectionName : this . connectionName ?. getValue ( dc . state ) ,
364
381
title,
365
382
text,
366
383
} ;
384
+
385
+ // Send OAuthCard to root bot. The root bot could attempt to do a token exchange or if it cannot do token
386
+ // exchange for this connection it will let the card get to the user to allow them to sign in.
367
387
return OAuthPrompt . sendOAuthCard ( settings , dc . context , prompt ) ;
368
388
}
369
389
0 commit comments