@microsoft/teamsfx 2.0.0-experimental.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/dist/index.esm2017.js +429 -229
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +1644 -549
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +447 -229
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +1700 -547
- package/dist/index.node.cjs.js.map +1 -1
- package/package.json +11 -10
- package/types/teamsfx.d.ts +2197 -1648
- package/CHANGELOG.md +0 -28
- package/NOTICE.txt +0 -9242
package/dist/index.node.cjs.js
CHANGED
|
@@ -46,7 +46,6 @@ var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
|
|
|
46
46
|
// Licensed under the MIT license.
|
|
47
47
|
/**
|
|
48
48
|
* Error code to trace the error types.
|
|
49
|
-
* @beta
|
|
50
49
|
*/
|
|
51
50
|
exports.ErrorCode = void 0;
|
|
52
51
|
(function (ErrorCode) {
|
|
@@ -70,6 +69,30 @@ exports.ErrorCode = void 0;
|
|
|
70
69
|
* Channel is not supported error.
|
|
71
70
|
*/
|
|
72
71
|
ErrorCode["ChannelNotSupported"] = "ChannelNotSupported";
|
|
72
|
+
/**
|
|
73
|
+
* Failed to retrieve sso token
|
|
74
|
+
*/
|
|
75
|
+
ErrorCode["FailedToRetrieveSsoToken"] = "FailedToRetrieveSsoToken";
|
|
76
|
+
/**
|
|
77
|
+
* Failed to process sso handler
|
|
78
|
+
*/
|
|
79
|
+
ErrorCode["FailedToProcessSsoHandler"] = "FailedToProcessSsoHandler";
|
|
80
|
+
/**
|
|
81
|
+
* Cannot find command
|
|
82
|
+
*/
|
|
83
|
+
ErrorCode["CannotFindCommand"] = "CannotFindCommand";
|
|
84
|
+
/**
|
|
85
|
+
* Failed to run sso step
|
|
86
|
+
*/
|
|
87
|
+
ErrorCode["FailedToRunSsoStep"] = "FailedToRunSsoStep";
|
|
88
|
+
/**
|
|
89
|
+
* Failed to run dedup step
|
|
90
|
+
*/
|
|
91
|
+
ErrorCode["FailedToRunDedupStep"] = "FailedToRunDedupStep";
|
|
92
|
+
/**
|
|
93
|
+
* Sso activity handler is undefined
|
|
94
|
+
*/
|
|
95
|
+
ErrorCode["SsoActivityHandlerIsUndefined"] = "SsoActivityHandlerIsUndefined";
|
|
73
96
|
/**
|
|
74
97
|
* Runtime is not supported error.
|
|
75
98
|
*/
|
|
@@ -125,6 +148,15 @@ ErrorMessage.NodejsRuntimeNotSupported = "{0} is not supported in Node.";
|
|
|
125
148
|
ErrorMessage.FailToAcquireTokenOnBehalfOfUser = "Failed to acquire access token on behalf of user: {0}";
|
|
126
149
|
// ChannelNotSupported Error
|
|
127
150
|
ErrorMessage.OnlyMSTeamsChannelSupported = "{0} is only supported in MS Teams Channel";
|
|
151
|
+
ErrorMessage.FailedToProcessSsoHandler = "Failed to process sso handler: {0}";
|
|
152
|
+
// FailedToRetrieveSsoToken Error
|
|
153
|
+
ErrorMessage.FailedToRetrieveSsoToken = "Failed to retrieve sso token, user failed to finish the AAD consent flow.";
|
|
154
|
+
// CannotFindCommand Error
|
|
155
|
+
ErrorMessage.CannotFindCommand = "Cannot find command: {0}";
|
|
156
|
+
ErrorMessage.FailedToRunSsoStep = "Failed to run dialog to retrieve sso token: {0}";
|
|
157
|
+
ErrorMessage.FailedToRunDedupStep = "Failed to run dialog to remove duplicated messages: {0}";
|
|
158
|
+
// SsoActivityHandlerIsUndefined Error
|
|
159
|
+
ErrorMessage.SsoActivityHandlerIsNull = "Sso command can only be used or added when sso activity handler is not undefined";
|
|
128
160
|
// IdentityTypeNotSupported Error
|
|
129
161
|
ErrorMessage.IdentityTypeNotSupported = "{0} identity is not supported in {1}";
|
|
130
162
|
// AuthorizationInfoError
|
|
@@ -135,10 +167,9 @@ ErrorMessage.EmptyParameter = "Parameter {0} is empty";
|
|
|
135
167
|
ErrorMessage.DuplicateHttpsOptionProperty = "Axios HTTPS agent already defined value for property {0}";
|
|
136
168
|
ErrorMessage.DuplicateApiKeyInHeader = "The request already defined api key in request header with name {0}.";
|
|
137
169
|
ErrorMessage.DuplicateApiKeyInQueryParam = "The request already defined api key in query parameter with name {0}.";
|
|
170
|
+
ErrorMessage.OnlySupportInQueryActivity = "The handleMessageExtensionQueryWithToken only support in handleTeamsMessagingExtensionQuery with composeExtension/query type.";
|
|
138
171
|
/**
|
|
139
172
|
* Error class with code and message thrown by the SDK.
|
|
140
|
-
*
|
|
141
|
-
* @beta
|
|
142
173
|
*/
|
|
143
174
|
class ErrorWithCode extends Error {
|
|
144
175
|
/**
|
|
@@ -146,8 +177,6 @@ class ErrorWithCode extends Error {
|
|
|
146
177
|
*
|
|
147
178
|
* @param {string} message - error message.
|
|
148
179
|
* @param {ErrorCode} code - error code.
|
|
149
|
-
*
|
|
150
|
-
* @beta
|
|
151
180
|
*/
|
|
152
181
|
constructor(message, code) {
|
|
153
182
|
if (!code) {
|
|
@@ -165,8 +194,6 @@ class ErrorWithCode extends Error {
|
|
|
165
194
|
// Licensed under the MIT license.
|
|
166
195
|
/**
|
|
167
196
|
* Log level.
|
|
168
|
-
*
|
|
169
|
-
* @beta
|
|
170
197
|
*/
|
|
171
198
|
exports.LogLevel = void 0;
|
|
172
199
|
(function (LogLevel) {
|
|
@@ -191,8 +218,6 @@ exports.LogLevel = void 0;
|
|
|
191
218
|
* Update log level helper.
|
|
192
219
|
*
|
|
193
220
|
* @param { LogLevel } level - log level in configuration
|
|
194
|
-
*
|
|
195
|
-
* @beta
|
|
196
221
|
*/
|
|
197
222
|
function setLogLevel(level) {
|
|
198
223
|
internalLogger.level = level;
|
|
@@ -201,8 +226,6 @@ function setLogLevel(level) {
|
|
|
201
226
|
* Get log level.
|
|
202
227
|
*
|
|
203
228
|
* @returns Log level
|
|
204
|
-
*
|
|
205
|
-
* @beta
|
|
206
229
|
*/
|
|
207
230
|
function getLogLevel() {
|
|
208
231
|
return internalLogger.level;
|
|
@@ -277,8 +300,6 @@ const internalLogger = new InternalLogger();
|
|
|
277
300
|
* error: console.error,
|
|
278
301
|
* });
|
|
279
302
|
* ```
|
|
280
|
-
*
|
|
281
|
-
* @beta
|
|
282
303
|
*/
|
|
283
304
|
function setLogger(logger) {
|
|
284
305
|
internalLogger.customLogger = logger;
|
|
@@ -296,8 +317,6 @@ function setLogger(logger) {
|
|
|
296
317
|
* }
|
|
297
318
|
* });
|
|
298
319
|
* ```
|
|
299
|
-
*
|
|
300
|
-
* @beta
|
|
301
320
|
*/
|
|
302
321
|
function setLogFunction(logFunction) {
|
|
303
322
|
internalLogger.customLogFunction = logFunction;
|
|
@@ -340,6 +359,7 @@ function getUserInfoFromSsoToken(ssoToken) {
|
|
|
340
359
|
const userInfo = {
|
|
341
360
|
displayName: tokenObject.name,
|
|
342
361
|
objectId: tokenObject.oid,
|
|
362
|
+
tenantId: tokenObject.tid,
|
|
343
363
|
preferredUserName: "",
|
|
344
364
|
};
|
|
345
365
|
if (tokenObject.ver === "2.0") {
|
|
@@ -461,23 +481,8 @@ function parseCertificate(certificateContent) {
|
|
|
461
481
|
*
|
|
462
482
|
* @remarks
|
|
463
483
|
* Only works in in server side.
|
|
464
|
-
*
|
|
465
|
-
* @beta
|
|
466
484
|
*/
|
|
467
485
|
class AppCredential {
|
|
468
|
-
/**
|
|
469
|
-
* Constructor of AppCredential.
|
|
470
|
-
*
|
|
471
|
-
* @remarks
|
|
472
|
-
* Only works in in server side.
|
|
473
|
-
*
|
|
474
|
-
* @param {AuthenticationConfiguration} authConfig - The authentication configuration. Use environment variables if not provided.
|
|
475
|
-
*
|
|
476
|
-
* @throws {@link ErrorCode|InvalidConfiguration} when client id, client secret or tenant id is not found in config.
|
|
477
|
-
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
|
|
478
|
-
*
|
|
479
|
-
* @beta
|
|
480
|
-
*/
|
|
481
486
|
constructor(authConfig) {
|
|
482
487
|
internalLogger.info("Create M365 tenant credential");
|
|
483
488
|
const config = this.loadAndValidateConfig(authConfig);
|
|
@@ -506,8 +511,6 @@ class AppCredential {
|
|
|
506
511
|
*
|
|
507
512
|
* @returns Access token with expected scopes.
|
|
508
513
|
* Throw error if get access token failed.
|
|
509
|
-
*
|
|
510
|
-
* @beta
|
|
511
514
|
*/
|
|
512
515
|
getToken(scopes, options) {
|
|
513
516
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
@@ -549,7 +552,10 @@ class AppCredential {
|
|
|
549
552
|
*/
|
|
550
553
|
loadAndValidateConfig(config) {
|
|
551
554
|
internalLogger.verbose("Validate authentication configuration");
|
|
552
|
-
if (config.clientId &&
|
|
555
|
+
if (config.clientId &&
|
|
556
|
+
(config.clientSecret || config.certificateContent) &&
|
|
557
|
+
config.tenantId &&
|
|
558
|
+
config.authorityHost) {
|
|
553
559
|
return config;
|
|
554
560
|
}
|
|
555
561
|
const missingValues = [];
|
|
@@ -562,6 +568,9 @@ class AppCredential {
|
|
|
562
568
|
if (!config.tenantId) {
|
|
563
569
|
missingValues.push("tenantId");
|
|
564
570
|
}
|
|
571
|
+
if (!config.authorityHost) {
|
|
572
|
+
missingValues.push("authorityHost");
|
|
573
|
+
}
|
|
565
574
|
const errorMsg = formatString(ErrorMessage.InvalidConfiguration, missingValues.join(", "), "undefined");
|
|
566
575
|
internalLogger.error(errorMsg);
|
|
567
576
|
throw new ErrorWithCode(errorMsg, exports.ErrorCode.InvalidConfiguration);
|
|
@@ -579,25 +588,8 @@ class AppCredential {
|
|
|
579
588
|
*
|
|
580
589
|
* @remarks
|
|
581
590
|
* Can only be used in server side.
|
|
582
|
-
*
|
|
583
|
-
* @beta
|
|
584
591
|
*/
|
|
585
592
|
class OnBehalfOfUserCredential {
|
|
586
|
-
/**
|
|
587
|
-
* Constructor of OnBehalfOfUserCredential
|
|
588
|
-
*
|
|
589
|
-
* @remarks
|
|
590
|
-
* Only works in in server side.
|
|
591
|
-
*
|
|
592
|
-
* @param {string} ssoToken - User token provided by Teams SSO feature.
|
|
593
|
-
* @param {AuthenticationConfiguration} config - The authentication configuration. Use environment variables if not provided.
|
|
594
|
-
*
|
|
595
|
-
* @throws {@link ErrorCode|InvalidConfiguration} when client id, client secret, certificate content, authority host or tenant id is not found in config.
|
|
596
|
-
* @throws {@link ErrorCode|InternalError} when SSO token is not valid.
|
|
597
|
-
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
|
|
598
|
-
*
|
|
599
|
-
* @beta
|
|
600
|
-
*/
|
|
601
593
|
constructor(ssoToken, config) {
|
|
602
594
|
internalLogger.info("Get on behalf of user credential");
|
|
603
595
|
const missingConfigurations = [];
|
|
@@ -657,8 +649,6 @@ class OnBehalfOfUserCredential {
|
|
|
657
649
|
* @remarks
|
|
658
650
|
* If scopes is empty string or array, it returns SSO token.
|
|
659
651
|
* If scopes is non-empty, it returns access token for target scope.
|
|
660
|
-
*
|
|
661
|
-
* @beta
|
|
662
652
|
*/
|
|
663
653
|
getToken(scopes, options) {
|
|
664
654
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
@@ -711,8 +701,6 @@ class OnBehalfOfUserCredential {
|
|
|
711
701
|
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
|
|
712
702
|
*
|
|
713
703
|
* @returns Basic user info with user displayName, objectId and preferredUserName.
|
|
714
|
-
*
|
|
715
|
-
* @beta
|
|
716
704
|
*/
|
|
717
705
|
getUserInfo() {
|
|
718
706
|
internalLogger.info("Get basic user info from SSO token");
|
|
@@ -744,26 +732,20 @@ class OnBehalfOfUserCredential {
|
|
|
744
732
|
*
|
|
745
733
|
* @remarks
|
|
746
734
|
* Can only be used within Teams.
|
|
747
|
-
*
|
|
748
|
-
* @beta
|
|
749
735
|
*/
|
|
750
736
|
class TeamsUserCredential {
|
|
751
|
-
/**
|
|
752
|
-
* Constructor of TeamsUserCredential.
|
|
753
|
-
* @remarks
|
|
754
|
-
* Can only be used within Teams.
|
|
755
|
-
* @beta
|
|
756
|
-
*/
|
|
757
737
|
constructor(authConfig) {
|
|
758
738
|
throw new ErrorWithCode(formatString(ErrorMessage.NodejsRuntimeNotSupported, "TeamsUserCredential"), exports.ErrorCode.RuntimeNotSupported);
|
|
759
739
|
}
|
|
760
740
|
/**
|
|
761
741
|
* Popup login page to get user's access token with specific scopes.
|
|
742
|
+
*
|
|
743
|
+
* @param {string[]} resources - The optional list of resources for full trust Teams apps.
|
|
744
|
+
*
|
|
762
745
|
* @remarks
|
|
763
746
|
* Can only be used within Teams.
|
|
764
|
-
* @beta
|
|
765
747
|
*/
|
|
766
|
-
login(scopes) {
|
|
748
|
+
login(scopes, resources) {
|
|
767
749
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
768
750
|
throw new ErrorWithCode(formatString(ErrorMessage.NodejsRuntimeNotSupported, "TeamsUserCredential"), exports.ErrorCode.RuntimeNotSupported);
|
|
769
751
|
});
|
|
@@ -772,7 +754,6 @@ class TeamsUserCredential {
|
|
|
772
754
|
* Get access token from credential.
|
|
773
755
|
* @remarks
|
|
774
756
|
* Can only be used within Teams.
|
|
775
|
-
* @beta
|
|
776
757
|
*/
|
|
777
758
|
getToken(scopes, options) {
|
|
778
759
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
@@ -781,11 +762,13 @@ class TeamsUserCredential {
|
|
|
781
762
|
}
|
|
782
763
|
/**
|
|
783
764
|
* Get basic user info from SSO token
|
|
765
|
+
*
|
|
766
|
+
* @param {string[]} resources - The optional list of resources for full trust Teams apps.
|
|
767
|
+
*
|
|
784
768
|
* @remarks
|
|
785
769
|
* Can only be used within Teams.
|
|
786
|
-
* @beta
|
|
787
770
|
*/
|
|
788
|
-
getUserInfo() {
|
|
771
|
+
getUserInfo(resources) {
|
|
789
772
|
throw new ErrorWithCode(formatString(ErrorMessage.NodejsRuntimeNotSupported, "TeamsUserCredential"), exports.ErrorCode.RuntimeNotSupported);
|
|
790
773
|
}
|
|
791
774
|
}
|
|
@@ -794,24 +777,10 @@ class TeamsUserCredential {
|
|
|
794
777
|
const defaultScope = "https://graph.microsoft.com/.default";
|
|
795
778
|
/**
|
|
796
779
|
* Microsoft Graph auth provider for Teams Framework
|
|
797
|
-
*
|
|
798
|
-
* @beta
|
|
799
780
|
*/
|
|
800
781
|
class MsGraphAuthProvider {
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
*
|
|
804
|
-
* @param {TeamsFx} teamsfx - Used to provide configuration and auth.
|
|
805
|
-
* @param {string | string[]} scopes - The list of scopes for which the token will have access.
|
|
806
|
-
*
|
|
807
|
-
* @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
|
|
808
|
-
*
|
|
809
|
-
* @returns An instance of MsGraphAuthProvider.
|
|
810
|
-
*
|
|
811
|
-
* @beta
|
|
812
|
-
*/
|
|
813
|
-
constructor(teamsfx, scopes) {
|
|
814
|
-
this.teamsfx = teamsfx;
|
|
782
|
+
constructor(credentialOrTeamsFx, scopes) {
|
|
783
|
+
this.credentialOrTeamsFx = credentialOrTeamsFx;
|
|
815
784
|
let scopesStr = defaultScope;
|
|
816
785
|
if (scopes) {
|
|
817
786
|
validateScopesType(scopes);
|
|
@@ -838,7 +807,15 @@ class MsGraphAuthProvider {
|
|
|
838
807
|
getAccessToken() {
|
|
839
808
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
840
809
|
internalLogger.info(`Get Graph Access token with scopes: '${this.scopes}'`);
|
|
841
|
-
|
|
810
|
+
let accessToken;
|
|
811
|
+
if (this.credentialOrTeamsFx.getCredential) {
|
|
812
|
+
accessToken = yield this.credentialOrTeamsFx
|
|
813
|
+
.getCredential()
|
|
814
|
+
.getToken(this.scopes);
|
|
815
|
+
}
|
|
816
|
+
else {
|
|
817
|
+
accessToken = yield this.credentialOrTeamsFx.getToken(this.scopes);
|
|
818
|
+
}
|
|
842
819
|
return new Promise((resolve, reject) => {
|
|
843
820
|
if (accessToken) {
|
|
844
821
|
resolve(accessToken.token);
|
|
@@ -856,7 +833,6 @@ class MsGraphAuthProvider {
|
|
|
856
833
|
// Copyright (c) Microsoft Corporation.
|
|
857
834
|
/**
|
|
858
835
|
* Get Microsoft graph client.
|
|
859
|
-
*
|
|
860
836
|
* @example
|
|
861
837
|
* Get Microsoft graph client by TokenCredential
|
|
862
838
|
* ```typescript
|
|
@@ -902,8 +878,6 @@ class MsGraphAuthProvider {
|
|
|
902
878
|
* @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
|
|
903
879
|
*
|
|
904
880
|
* @returns Graph client with specified scopes.
|
|
905
|
-
*
|
|
906
|
-
* @beta
|
|
907
881
|
*/
|
|
908
882
|
function createMicrosoftGraphClient(teamsfx, scopes) {
|
|
909
883
|
internalLogger.info("Create Microsoft Graph Client");
|
|
@@ -912,6 +886,66 @@ function createMicrosoftGraphClient(teamsfx, scopes) {
|
|
|
912
886
|
authProvider,
|
|
913
887
|
});
|
|
914
888
|
return graphClient;
|
|
889
|
+
}
|
|
890
|
+
// eslint-disable-next-line no-secrets/no-secrets
|
|
891
|
+
/**
|
|
892
|
+
* Get Microsoft graph client.
|
|
893
|
+
* @example
|
|
894
|
+
* Get Microsoft graph client by TokenCredential
|
|
895
|
+
* ```typescript
|
|
896
|
+
* // In browser: TeamsUserCredential
|
|
897
|
+
* const authConfig: TeamsUserCredentialAuthConfig = {
|
|
898
|
+
* clientId: "xxx",
|
|
899
|
+
initiateLoginEndpoint: "https://xxx/auth-start.html",
|
|
900
|
+
* };
|
|
901
|
+
|
|
902
|
+
* const credential = new TeamsUserCredential(authConfig);
|
|
903
|
+
|
|
904
|
+
* const scope = "User.Read";
|
|
905
|
+
* await credential.login(scope);
|
|
906
|
+
|
|
907
|
+
* const client = createMicrosoftGraphClientWithCredential(credential, scope);
|
|
908
|
+
|
|
909
|
+
* // In node: OnBehalfOfUserCredential
|
|
910
|
+
* const oboAuthConfig: OnBehalfOfCredentialAuthConfig = {
|
|
911
|
+
* authorityHost: "xxx",
|
|
912
|
+
* clientId: "xxx",
|
|
913
|
+
* tenantId: "xxx",
|
|
914
|
+
* clientSecret: "xxx",
|
|
915
|
+
* };
|
|
916
|
+
|
|
917
|
+
* const oboCredential = new OnBehalfOfUserCredential(ssoToken, oboAuthConfig);
|
|
918
|
+
* const scope = "User.Read";
|
|
919
|
+
* const client = createMicrosoftGraphClientWithCredential(oboCredential, scope);
|
|
920
|
+
|
|
921
|
+
* // In node: AppCredential
|
|
922
|
+
* const appAuthConfig: AppCredentialAuthConfig = {
|
|
923
|
+
* authorityHost: "xxx",
|
|
924
|
+
* clientId: "xxx",
|
|
925
|
+
* tenantId: "xxx",
|
|
926
|
+
* clientSecret: "xxx",
|
|
927
|
+
* };
|
|
928
|
+
* const appCredential = new AppCredential(appAuthConfig);
|
|
929
|
+
* const scope = "User.Read";
|
|
930
|
+
* const client = createMicrosoftGraphClientWithCredential(appCredential, scope);
|
|
931
|
+
*
|
|
932
|
+
* const profile = await client.api("/me").get();
|
|
933
|
+
* ```
|
|
934
|
+
*
|
|
935
|
+
* @param {TokenCredential} credential - Used to provide configuration and auth.
|
|
936
|
+
* @param scopes - The array of Microsoft Token scope of access. Default value is `[.default]`.
|
|
937
|
+
*
|
|
938
|
+
* @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
|
|
939
|
+
*
|
|
940
|
+
* @returns Graph client with specified scopes.
|
|
941
|
+
*/
|
|
942
|
+
function createMicrosoftGraphClientWithCredential(credential, scopes) {
|
|
943
|
+
internalLogger.info("Create Microsoft Graph Client");
|
|
944
|
+
const authProvider = new MsGraphAuthProvider(credential, scopes);
|
|
945
|
+
const graphClient = microsoftGraphClient.Client.initWithMiddleware({
|
|
946
|
+
authProvider,
|
|
947
|
+
});
|
|
948
|
+
return graphClient;
|
|
915
949
|
}
|
|
916
950
|
|
|
917
951
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -923,6 +957,8 @@ const defaultSQLScope = "https://database.windows.net/";
|
|
|
923
957
|
/**
|
|
924
958
|
* Generate connection configuration consumed by tedious.
|
|
925
959
|
*
|
|
960
|
+
* @deprecated we recommend you compose your own Tedious configuration for better flexibility.
|
|
961
|
+
*
|
|
926
962
|
* @param {TeamsFx} teamsfx - Used to provide configuration and auth
|
|
927
963
|
* @param { string? } databaseName - specify database name to override default one if there are multiple databases.
|
|
928
964
|
*
|
|
@@ -931,8 +967,6 @@ const defaultSQLScope = "https://database.windows.net/";
|
|
|
931
967
|
* @throws {@link ErrorCode|InvalidConfiguration} when SQL config resource configuration is invalid.
|
|
932
968
|
* @throws {@link ErrorCode|InternalError} when get user MSI token failed or MSI token is invalid.
|
|
933
969
|
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
|
|
934
|
-
*
|
|
935
|
-
* @beta
|
|
936
970
|
*/
|
|
937
971
|
function getTediousConnectionConfig(teamsfx, databaseName) {
|
|
938
972
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
@@ -1091,8 +1125,6 @@ var TediousAuthenticationType;
|
|
|
1091
1125
|
// Licensed under the MIT license.
|
|
1092
1126
|
/**
|
|
1093
1127
|
* Identity type to use in authentication.
|
|
1094
|
-
*
|
|
1095
|
-
* @beta
|
|
1096
1128
|
*/
|
|
1097
1129
|
exports.IdentityType = void 0;
|
|
1098
1130
|
(function (IdentityType) {
|
|
@@ -1110,8 +1142,6 @@ exports.IdentityType = void 0;
|
|
|
1110
1142
|
const invokeResponseType = "invokeResponse";
|
|
1111
1143
|
/**
|
|
1112
1144
|
* Response body returned for a token exchange invoke activity.
|
|
1113
|
-
*
|
|
1114
|
-
* @beta
|
|
1115
1145
|
*/
|
|
1116
1146
|
class TokenExchangeInvokeResponse {
|
|
1117
1147
|
constructor(id, failureDetail) {
|
|
@@ -1166,28 +1196,22 @@ class TokenExchangeInvokeResponse {
|
|
|
1166
1196
|
* }
|
|
1167
1197
|
* ]));
|
|
1168
1198
|
* ```
|
|
1169
|
-
*
|
|
1170
|
-
* @beta
|
|
1171
1199
|
*/
|
|
1172
1200
|
class TeamsBotSsoPrompt extends botbuilderDialogs.Dialog {
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
this.teamsfx = teamsfx;
|
|
1188
|
-
this.settings = settings;
|
|
1189
|
-
validateScopesType(settings.scopes);
|
|
1190
|
-
this.loadAndValidateConfig();
|
|
1201
|
+
constructor(authConfig, ...args) {
|
|
1202
|
+
super(arguments.length === 3 ? args[0] : args[1]);
|
|
1203
|
+
if (authConfig.getCredential) {
|
|
1204
|
+
const teamsfx = authConfig;
|
|
1205
|
+
this.authConfig = this.loadAndValidateConfig(teamsfx);
|
|
1206
|
+
this.initiateLoginEndpoint = teamsfx.getConfig("initiateLoginEndpoint");
|
|
1207
|
+
this.settings = args[1];
|
|
1208
|
+
}
|
|
1209
|
+
else {
|
|
1210
|
+
this.initiateLoginEndpoint = args[0];
|
|
1211
|
+
this.authConfig = authConfig;
|
|
1212
|
+
this.settings = args[2];
|
|
1213
|
+
}
|
|
1214
|
+
validateScopesType(this.settings.scopes);
|
|
1191
1215
|
internalLogger.info("Create a new Teams Bot SSO Prompt");
|
|
1192
1216
|
}
|
|
1193
1217
|
/**
|
|
@@ -1203,8 +1227,6 @@ class TeamsBotSsoPrompt extends botbuilderDialogs.Dialog {
|
|
|
1203
1227
|
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
|
|
1204
1228
|
*
|
|
1205
1229
|
* @returns A `Promise` representing the asynchronous operation.
|
|
1206
|
-
*
|
|
1207
|
-
* @beta
|
|
1208
1230
|
*/
|
|
1209
1231
|
beginDialog(dc) {
|
|
1210
1232
|
var _a;
|
|
@@ -1254,8 +1276,6 @@ class TeamsBotSsoPrompt extends botbuilderDialogs.Dialog {
|
|
|
1254
1276
|
*
|
|
1255
1277
|
* @throws {@link ErrorCode|ChannelNotSupported} when bot channel is not MS Teams.
|
|
1256
1278
|
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
|
|
1257
|
-
*
|
|
1258
|
-
* @beta
|
|
1259
1279
|
*/
|
|
1260
1280
|
continueDialog(dc) {
|
|
1261
1281
|
var _a;
|
|
@@ -1292,30 +1312,45 @@ class TeamsBotSsoPrompt extends botbuilderDialogs.Dialog {
|
|
|
1292
1312
|
}
|
|
1293
1313
|
});
|
|
1294
1314
|
}
|
|
1295
|
-
loadAndValidateConfig() {
|
|
1296
|
-
if (
|
|
1297
|
-
const errorMsg = formatString(ErrorMessage.IdentityTypeNotSupported,
|
|
1315
|
+
loadAndValidateConfig(teamsfx) {
|
|
1316
|
+
if (teamsfx.getIdentityType() !== exports.IdentityType.User) {
|
|
1317
|
+
const errorMsg = formatString(ErrorMessage.IdentityTypeNotSupported, teamsfx.getIdentityType().toString(), "TeamsBotSsoPrompt");
|
|
1298
1318
|
internalLogger.error(errorMsg);
|
|
1299
1319
|
throw new ErrorWithCode(errorMsg, exports.ErrorCode.IdentityTypeNotSupported);
|
|
1300
1320
|
}
|
|
1301
1321
|
const missingConfigurations = [];
|
|
1302
|
-
if (!
|
|
1322
|
+
if (!teamsfx.hasConfig("initiateLoginEndpoint")) {
|
|
1303
1323
|
missingConfigurations.push("initiateLoginEndpoint");
|
|
1304
1324
|
}
|
|
1305
|
-
if (!
|
|
1325
|
+
if (!teamsfx.hasConfig("clientId")) {
|
|
1306
1326
|
missingConfigurations.push("clientId");
|
|
1307
1327
|
}
|
|
1308
|
-
if (!
|
|
1328
|
+
if (!teamsfx.hasConfig("tenantId")) {
|
|
1309
1329
|
missingConfigurations.push("tenantId");
|
|
1310
1330
|
}
|
|
1311
|
-
if (!this.teamsfx.hasConfig("applicationIdUri")) {
|
|
1312
|
-
missingConfigurations.push("applicationIdUri");
|
|
1313
|
-
}
|
|
1314
1331
|
if (missingConfigurations.length != 0) {
|
|
1315
1332
|
const errorMsg = formatString(ErrorMessage.InvalidConfiguration, missingConfigurations.join(", "), "undefined");
|
|
1316
1333
|
internalLogger.error(errorMsg);
|
|
1317
1334
|
throw new ErrorWithCode(errorMsg, exports.ErrorCode.InvalidConfiguration);
|
|
1318
1335
|
}
|
|
1336
|
+
let authConfig;
|
|
1337
|
+
if (teamsfx.getConfig("clientSecret")) {
|
|
1338
|
+
authConfig = {
|
|
1339
|
+
authorityHost: teamsfx.getConfig("authorityHost"),
|
|
1340
|
+
clientId: teamsfx.getConfig("clientId"),
|
|
1341
|
+
tenantId: teamsfx.getConfig("tenantId"),
|
|
1342
|
+
clientSecret: teamsfx.getConfig("clientSecret"),
|
|
1343
|
+
};
|
|
1344
|
+
}
|
|
1345
|
+
else {
|
|
1346
|
+
authConfig = {
|
|
1347
|
+
authorityHost: teamsfx.getConfig("authorityHost"),
|
|
1348
|
+
clientId: teamsfx.getConfig("clientId"),
|
|
1349
|
+
tenantId: teamsfx.getConfig("tenantId"),
|
|
1350
|
+
certificateContent: teamsfx.getConfig("certificateContent"),
|
|
1351
|
+
};
|
|
1352
|
+
}
|
|
1353
|
+
return authConfig;
|
|
1319
1354
|
}
|
|
1320
1355
|
/**
|
|
1321
1356
|
* Ensure bot is running in MS Teams since TeamsBotSsoPrompt is only supported in MS Teams channel.
|
|
@@ -1359,13 +1394,11 @@ class TeamsBotSsoPrompt extends botbuilderDialogs.Dialog {
|
|
|
1359
1394
|
*/
|
|
1360
1395
|
getSignInResource(loginHint) {
|
|
1361
1396
|
internalLogger.verbose("Get sign in authentication configuration");
|
|
1362
|
-
const signInLink = `${this.
|
|
1397
|
+
const signInLink = `${this.initiateLoginEndpoint}?scope=${encodeURI(this.settings.scopes.join(" "))}&clientId=${this.authConfig.clientId}&tenantId=${this.authConfig.tenantId}&loginHint=${loginHint}`;
|
|
1363
1398
|
internalLogger.verbose("Sign in link: " + signInLink);
|
|
1364
1399
|
const tokenExchangeResource = {
|
|
1365
1400
|
id: uuid.v4(),
|
|
1366
|
-
uri: this.teamsfx.getConfig("applicationIdUri").replace(/\/$/, "") + "/access_as_user",
|
|
1367
1401
|
};
|
|
1368
|
-
internalLogger.verbose("Token exchange resource uri: " + tokenExchangeResource.uri);
|
|
1369
1402
|
return {
|
|
1370
1403
|
signInLink: signInLink,
|
|
1371
1404
|
tokenExchangeResource: tokenExchangeResource,
|
|
@@ -1388,8 +1421,7 @@ class TeamsBotSsoPrompt extends botbuilderDialogs.Dialog {
|
|
|
1388
1421
|
}
|
|
1389
1422
|
else {
|
|
1390
1423
|
const ssoToken = context.activity.value.token;
|
|
1391
|
-
this.
|
|
1392
|
-
const credential = this.teamsfx.getCredential();
|
|
1424
|
+
const credential = new OnBehalfOfUserCredential(ssoToken, this.authConfig);
|
|
1393
1425
|
let exchangedToken;
|
|
1394
1426
|
try {
|
|
1395
1427
|
exchangedToken = yield credential.getToken(this.settings.scopes);
|
|
@@ -1466,8 +1498,6 @@ class TeamsBotSsoPrompt extends botbuilderDialogs.Dialog {
|
|
|
1466
1498
|
* ```typescript
|
|
1467
1499
|
* const client = createApiClient("https://my-api-endpoint-base-url", new BasicAuthProvider("xxx","xxx"));
|
|
1468
1500
|
* ```
|
|
1469
|
-
*
|
|
1470
|
-
* @beta
|
|
1471
1501
|
*/
|
|
1472
1502
|
function createApiClient(apiEndpoint, authProvider) {
|
|
1473
1503
|
// Add a request interceptor
|
|
@@ -1485,14 +1515,10 @@ function createApiClient(apiEndpoint, authProvider) {
|
|
|
1485
1515
|
// Copyright (c) Microsoft Corporation.
|
|
1486
1516
|
/**
|
|
1487
1517
|
* Provider that handles Bearer Token authentication
|
|
1488
|
-
*
|
|
1489
|
-
* @beta
|
|
1490
1518
|
*/
|
|
1491
1519
|
class BearerTokenAuthProvider {
|
|
1492
1520
|
/**
|
|
1493
1521
|
* @param { () => Promise<string> } getToken - Function that returns the content of bearer token used in http request
|
|
1494
|
-
*
|
|
1495
|
-
* @beta
|
|
1496
1522
|
*/
|
|
1497
1523
|
constructor(getToken) {
|
|
1498
1524
|
this.getToken = getToken;
|
|
@@ -1506,8 +1532,6 @@ class BearerTokenAuthProvider {
|
|
|
1506
1532
|
* @returns Updated axios request config.
|
|
1507
1533
|
*
|
|
1508
1534
|
* @throws {@link ErrorCode|AuthorizationInfoAlreadyExists} - when Authorization header already exists in request configuration.
|
|
1509
|
-
*
|
|
1510
|
-
* @beta
|
|
1511
1535
|
*/
|
|
1512
1536
|
AddAuthenticationInfo(config) {
|
|
1513
1537
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
@@ -1527,8 +1551,6 @@ class BearerTokenAuthProvider {
|
|
|
1527
1551
|
// Copyright (c) Microsoft Corporation.
|
|
1528
1552
|
/**
|
|
1529
1553
|
* Provider that handles Basic authentication
|
|
1530
|
-
*
|
|
1531
|
-
* @beta
|
|
1532
1554
|
*/
|
|
1533
1555
|
class BasicAuthProvider {
|
|
1534
1556
|
/**
|
|
@@ -1538,8 +1560,6 @@ class BasicAuthProvider {
|
|
|
1538
1560
|
*
|
|
1539
1561
|
* @throws {@link ErrorCode|InvalidParameter} - when username or password is empty.
|
|
1540
1562
|
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
|
|
1541
|
-
*
|
|
1542
|
-
* @beta
|
|
1543
1563
|
*/
|
|
1544
1564
|
constructor(userName, password) {
|
|
1545
1565
|
if (!userName) {
|
|
@@ -1561,8 +1581,6 @@ class BasicAuthProvider {
|
|
|
1561
1581
|
*
|
|
1562
1582
|
* @throws {@link ErrorCode|AuthorizationInfoAlreadyExists} - when Authorization header or auth property already exists in request configuration.
|
|
1563
1583
|
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
|
|
1564
|
-
*
|
|
1565
|
-
* @beta
|
|
1566
1584
|
*/
|
|
1567
1585
|
AddAuthenticationInfo(config) {
|
|
1568
1586
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
@@ -1584,8 +1602,6 @@ class BasicAuthProvider {
|
|
|
1584
1602
|
// Copyright (c) Microsoft Corporation.
|
|
1585
1603
|
/**
|
|
1586
1604
|
* Provider that handles API Key authentication
|
|
1587
|
-
*
|
|
1588
|
-
* @beta
|
|
1589
1605
|
*/
|
|
1590
1606
|
class ApiKeyProvider {
|
|
1591
1607
|
/**
|
|
@@ -1596,8 +1612,6 @@ class ApiKeyProvider {
|
|
|
1596
1612
|
*
|
|
1597
1613
|
* @throws {@link ErrorCode|InvalidParameter} - when key name or key value is empty.
|
|
1598
1614
|
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
|
|
1599
|
-
*
|
|
1600
|
-
* @beta
|
|
1601
1615
|
*/
|
|
1602
1616
|
constructor(keyName, keyValue, keyLocation) {
|
|
1603
1617
|
if (!keyName) {
|
|
@@ -1620,8 +1634,6 @@ class ApiKeyProvider {
|
|
|
1620
1634
|
*
|
|
1621
1635
|
* @throws {@link ErrorCode|AuthorizationInfoAlreadyExists} - when API key already exists in request header or url query parameter.
|
|
1622
1636
|
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
|
|
1623
|
-
*
|
|
1624
|
-
* @beta
|
|
1625
1637
|
*/
|
|
1626
1638
|
AddAuthenticationInfo(config) {
|
|
1627
1639
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
@@ -1639,8 +1651,12 @@ class ApiKeyProvider {
|
|
|
1639
1651
|
if (!config.params) {
|
|
1640
1652
|
config.params = {};
|
|
1641
1653
|
}
|
|
1642
|
-
|
|
1643
|
-
if (config.
|
|
1654
|
+
let urlHasDefinedApiKey = false;
|
|
1655
|
+
if (config.url) {
|
|
1656
|
+
const url = new URL(config.url, config.baseURL);
|
|
1657
|
+
urlHasDefinedApiKey = url.searchParams.has(this.keyName);
|
|
1658
|
+
}
|
|
1659
|
+
if (config.params[this.keyName] || urlHasDefinedApiKey) {
|
|
1644
1660
|
throw new ErrorWithCode(formatString(ErrorMessage.DuplicateApiKeyInQueryParam, this.keyName), exports.ErrorCode.AuthorizationInfoAlreadyExists);
|
|
1645
1661
|
}
|
|
1646
1662
|
config.params[this.keyName] = this.keyValue;
|
|
@@ -1652,8 +1668,6 @@ class ApiKeyProvider {
|
|
|
1652
1668
|
}
|
|
1653
1669
|
/**
|
|
1654
1670
|
* Define available location for API Key location
|
|
1655
|
-
*
|
|
1656
|
-
* @beta
|
|
1657
1671
|
*/
|
|
1658
1672
|
exports.ApiKeyLocation = void 0;
|
|
1659
1673
|
(function (ApiKeyLocation) {
|
|
@@ -1670,8 +1684,6 @@ exports.ApiKeyLocation = void 0;
|
|
|
1670
1684
|
// Copyright (c) Microsoft Corporation.
|
|
1671
1685
|
/**
|
|
1672
1686
|
* Provider that handles Certificate authentication
|
|
1673
|
-
*
|
|
1674
|
-
* @beta
|
|
1675
1687
|
*/
|
|
1676
1688
|
class CertificateAuthProvider {
|
|
1677
1689
|
/**
|
|
@@ -1679,8 +1691,6 @@ class CertificateAuthProvider {
|
|
|
1679
1691
|
* @param { SecureContextOptions } certOption - information about the cert used in http requests
|
|
1680
1692
|
*
|
|
1681
1693
|
* @throws {@link ErrorCode|InvalidParameter} - when cert option is empty.
|
|
1682
|
-
*
|
|
1683
|
-
* @beta
|
|
1684
1694
|
*/
|
|
1685
1695
|
constructor(certOption) {
|
|
1686
1696
|
if (certOption && Object.keys(certOption).length !== 0) {
|
|
@@ -1699,8 +1709,6 @@ class CertificateAuthProvider {
|
|
|
1699
1709
|
* @returns Updated axios request config.
|
|
1700
1710
|
*
|
|
1701
1711
|
* @throws {@link ErrorCode|InvalidParameter} - when custom httpsAgent in the request has duplicate properties with certOption provided in constructor.
|
|
1702
|
-
*
|
|
1703
|
-
* @beta
|
|
1704
1712
|
*/
|
|
1705
1713
|
AddAuthenticationInfo(config) {
|
|
1706
1714
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
@@ -1786,7 +1794,6 @@ const ReservedKey = new Set([
|
|
|
1786
1794
|
]);
|
|
1787
1795
|
/**
|
|
1788
1796
|
* A class providing credential and configuration.
|
|
1789
|
-
* @beta
|
|
1790
1797
|
*/
|
|
1791
1798
|
class TeamsFx {
|
|
1792
1799
|
/**
|
|
@@ -1796,16 +1803,15 @@ class TeamsFx {
|
|
|
1796
1803
|
* @param customConfig - key/value pairs of customized configuration that overrides default ones.
|
|
1797
1804
|
*
|
|
1798
1805
|
* @throws {@link ErrorCode|IdentityTypeNotSupported} when setting app identity in browser.
|
|
1799
|
-
*
|
|
1800
|
-
* @beta
|
|
1801
1806
|
*/
|
|
1802
1807
|
constructor(identityType, customConfig) {
|
|
1803
1808
|
this.identityType = identityType !== null && identityType !== void 0 ? identityType : exports.IdentityType.User;
|
|
1804
1809
|
this.configuration = new Map();
|
|
1805
1810
|
this.loadFromEnv();
|
|
1806
1811
|
if (customConfig) {
|
|
1807
|
-
|
|
1808
|
-
|
|
1812
|
+
const myConfig = Object.assign({}, customConfig);
|
|
1813
|
+
for (const key of Object.keys(myConfig)) {
|
|
1814
|
+
const value = myConfig[key];
|
|
1809
1815
|
if (value) {
|
|
1810
1816
|
this.configuration.set(key, value);
|
|
1811
1817
|
}
|
|
@@ -1816,7 +1822,6 @@ class TeamsFx {
|
|
|
1816
1822
|
* Identity type set by user.
|
|
1817
1823
|
*
|
|
1818
1824
|
* @returns identity type.
|
|
1819
|
-
* @beta
|
|
1820
1825
|
*/
|
|
1821
1826
|
getIdentityType() {
|
|
1822
1827
|
return this.identityType;
|
|
@@ -1829,7 +1834,6 @@ class TeamsFx {
|
|
|
1829
1834
|
* identity is chose, will return {@link AppCredential}.
|
|
1830
1835
|
*
|
|
1831
1836
|
* @returns instance implements TokenCredential interface.
|
|
1832
|
-
* @beta
|
|
1833
1837
|
*/
|
|
1834
1838
|
getCredential() {
|
|
1835
1839
|
if (this.identityType === exports.IdentityType.User) {
|
|
@@ -1849,10 +1853,10 @@ class TeamsFx {
|
|
|
1849
1853
|
}
|
|
1850
1854
|
/**
|
|
1851
1855
|
* Get user information.
|
|
1856
|
+
* @param {string[]} resources - The optional list of resources for full trust Teams apps.
|
|
1852
1857
|
* @returns UserInfo object.
|
|
1853
|
-
* @beta
|
|
1854
1858
|
*/
|
|
1855
|
-
getUserInfo() {
|
|
1859
|
+
getUserInfo(resources) {
|
|
1856
1860
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
1857
1861
|
if (this.identityType !== exports.IdentityType.User) {
|
|
1858
1862
|
const errorMsg = formatString(ErrorMessage.IdentityTypeNotSupported, this.identityType.toString(), "TeamsFx");
|
|
@@ -1876,15 +1880,14 @@ class TeamsFx {
|
|
|
1876
1880
|
* await teamsfx.login("https://graph.microsoft.com/User.Read Calendars.Read"); // multiple scopes using string
|
|
1877
1881
|
* ```
|
|
1878
1882
|
* @param scopes - The list of scopes for which the token will have access, before that, we will request user to consent.
|
|
1883
|
+
* @param {string[]} resources - The optional list of resources for full trust Teams apps.
|
|
1879
1884
|
*
|
|
1880
1885
|
* @throws {@link ErrorCode|InternalError} when failed to login with unknown error.
|
|
1881
1886
|
* @throws {@link ErrorCode|ConsentFailed} when user canceled or failed to consent.
|
|
1882
1887
|
* @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
|
|
1883
1888
|
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
|
|
1884
|
-
*
|
|
1885
|
-
* @beta
|
|
1886
1889
|
*/
|
|
1887
|
-
login(scopes) {
|
|
1890
|
+
login(scopes, resources) {
|
|
1888
1891
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
1889
1892
|
throw new ErrorWithCode(formatString(ErrorMessage.NodejsRuntimeNotSupported, "login"), exports.ErrorCode.RuntimeNotSupported);
|
|
1890
1893
|
});
|
|
@@ -1893,7 +1896,6 @@ class TeamsFx {
|
|
|
1893
1896
|
* Set SSO token when using user identity in NodeJS.
|
|
1894
1897
|
* @param {string} ssoToken - used for on behalf of user flow.
|
|
1895
1898
|
* @returns self instance.
|
|
1896
|
-
* @beta
|
|
1897
1899
|
*/
|
|
1898
1900
|
setSsoToken(ssoToken) {
|
|
1899
1901
|
if (this.identityType !== exports.IdentityType.User) {
|
|
@@ -1906,7 +1908,6 @@ class TeamsFx {
|
|
|
1906
1908
|
* Usually used by service plugins to retrieve specific config
|
|
1907
1909
|
* @param {string} key - configuration key.
|
|
1908
1910
|
* @returns value in configuration.
|
|
1909
|
-
* @beta
|
|
1910
1911
|
*/
|
|
1911
1912
|
getConfig(key) {
|
|
1912
1913
|
const value = this.configuration.get(key);
|
|
@@ -1921,7 +1922,6 @@ class TeamsFx {
|
|
|
1921
1922
|
* Check the value of specific key.
|
|
1922
1923
|
* @param {string} key - configuration key.
|
|
1923
1924
|
* @returns true if corresponding value is not empty string.
|
|
1924
|
-
* @beta
|
|
1925
1925
|
*/
|
|
1926
1926
|
hasConfig(key) {
|
|
1927
1927
|
const value = this.configuration.get(key);
|
|
@@ -1930,7 +1930,6 @@ class TeamsFx {
|
|
|
1930
1930
|
/**
|
|
1931
1931
|
* Get all configurations.
|
|
1932
1932
|
* @returns key value mappings.
|
|
1933
|
-
* @beta
|
|
1934
1933
|
*/
|
|
1935
1934
|
getConfigs() {
|
|
1936
1935
|
const config = {};
|
|
@@ -1972,168 +1971,387 @@ class TeamsFx {
|
|
|
1972
1971
|
// Copyright (c) Microsoft Corporation.
|
|
1973
1972
|
// Licensed under the MIT license.
|
|
1974
1973
|
/**
|
|
1975
|
-
*
|
|
1974
|
+
* The target type where the notification will be sent to.
|
|
1975
|
+
*
|
|
1976
|
+
* @remarks
|
|
1977
|
+
* - "Channel" means to a team channel. (By default, notification to a team will be sent to its "General" channel.)
|
|
1978
|
+
* - "Group" means to a group chat.
|
|
1979
|
+
* - "Person" means to a personal chat.
|
|
1976
1980
|
*/
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1981
|
+
exports.NotificationTargetType = void 0;
|
|
1982
|
+
(function (NotificationTargetType) {
|
|
1983
|
+
/**
|
|
1984
|
+
* The notification will be sent to a team channel.
|
|
1985
|
+
* (By default, notification to a team will be sent to its "General" channel.)
|
|
1986
|
+
*/
|
|
1987
|
+
NotificationTargetType["Channel"] = "Channel";
|
|
1988
|
+
/**
|
|
1989
|
+
* The notification will be sent to a group chat.
|
|
1990
|
+
*/
|
|
1991
|
+
NotificationTargetType["Group"] = "Group";
|
|
1992
|
+
/**
|
|
1993
|
+
* The notification will be sent to a personal chat.
|
|
1994
|
+
*/
|
|
1995
|
+
NotificationTargetType["Person"] = "Person";
|
|
1996
|
+
})(exports.NotificationTargetType || (exports.NotificationTargetType = {}));
|
|
1997
|
+
/**
|
|
1998
|
+
* Options used to control how the response card will be sent to users.
|
|
1999
|
+
*/
|
|
2000
|
+
exports.AdaptiveCardResponse = void 0;
|
|
2001
|
+
(function (AdaptiveCardResponse) {
|
|
2002
|
+
/**
|
|
2003
|
+
* The response card will be replaced the current one for the interactor who trigger the action.
|
|
2004
|
+
*/
|
|
2005
|
+
AdaptiveCardResponse[AdaptiveCardResponse["ReplaceForInteractor"] = 0] = "ReplaceForInteractor";
|
|
2006
|
+
/**
|
|
2007
|
+
* The response card will be replaced the current one for all users in the chat.
|
|
2008
|
+
*/
|
|
2009
|
+
AdaptiveCardResponse[AdaptiveCardResponse["ReplaceForAll"] = 1] = "ReplaceForAll";
|
|
2010
|
+
/**
|
|
2011
|
+
* The response card will be sent as a new message for all users in the chat.
|
|
2012
|
+
*/
|
|
2013
|
+
AdaptiveCardResponse[AdaptiveCardResponse["NewForAll"] = 2] = "NewForAll";
|
|
2014
|
+
})(exports.AdaptiveCardResponse || (exports.AdaptiveCardResponse = {}));
|
|
2015
|
+
/**
|
|
2016
|
+
* Status code for an `application/vnd.microsoft.error` invoke response.
|
|
2017
|
+
*/
|
|
2018
|
+
exports.InvokeResponseErrorCode = void 0;
|
|
2019
|
+
(function (InvokeResponseErrorCode) {
|
|
2020
|
+
/**
|
|
2021
|
+
* Invalid request.
|
|
2022
|
+
*/
|
|
2023
|
+
InvokeResponseErrorCode[InvokeResponseErrorCode["BadRequest"] = 400] = "BadRequest";
|
|
2024
|
+
/**
|
|
2025
|
+
* Internal server error.
|
|
2026
|
+
*/
|
|
2027
|
+
InvokeResponseErrorCode[InvokeResponseErrorCode["InternalServerError"] = 500] = "InternalServerError";
|
|
2028
|
+
})(exports.InvokeResponseErrorCode || (exports.InvokeResponseErrorCode = {}));
|
|
2029
|
+
|
|
1980
2030
|
/**
|
|
2031
|
+
* Available response type for an adaptive card invoke response.
|
|
1981
2032
|
* @internal
|
|
1982
2033
|
*/
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
2034
|
+
var InvokeResponseType;
|
|
2035
|
+
(function (InvokeResponseType) {
|
|
2036
|
+
InvokeResponseType["AdaptiveCard"] = "application/vnd.microsoft.card.adaptive";
|
|
2037
|
+
InvokeResponseType["Message"] = "application/vnd.microsoft.activity.message";
|
|
2038
|
+
InvokeResponseType["Error"] = "application/vnd.microsoft.error";
|
|
2039
|
+
})(InvokeResponseType || (InvokeResponseType = {}));
|
|
2040
|
+
/**
|
|
2041
|
+
* Provides methods for formatting various invoke responses a bot can send to respond to an invoke request.
|
|
2042
|
+
*
|
|
2043
|
+
* @remarks
|
|
2044
|
+
* All of these functions return an {@link InvokeResponse} object, which can be
|
|
2045
|
+
* passed as input to generate a new `invokeResponse` activity.
|
|
2046
|
+
*
|
|
2047
|
+
* This example sends an invoke response that contains an adaptive card.
|
|
2048
|
+
*
|
|
2049
|
+
* ```typescript
|
|
2050
|
+
*
|
|
2051
|
+
* const myCard = {
|
|
2052
|
+
* type: "AdaptiveCard",
|
|
2053
|
+
* body: [
|
|
2054
|
+
* {
|
|
2055
|
+
* "type": "TextBlock",
|
|
2056
|
+
* "text": "This is a sample card"
|
|
2057
|
+
* }],
|
|
2058
|
+
* $schema: "http://adaptivecards.io/schemas/adaptive-card.json",
|
|
2059
|
+
* version: "1.4"
|
|
2060
|
+
* };
|
|
2061
|
+
*
|
|
2062
|
+
* const invokeResponse = InvokeResponseFactory.adaptiveCard(myCard);
|
|
2063
|
+
* await context.sendActivity({
|
|
2064
|
+
* type: ActivityTypes.InvokeResponse,
|
|
2065
|
+
* value: invokeResponse,
|
|
2066
|
+
* });
|
|
2067
|
+
* ```
|
|
2068
|
+
*/
|
|
2069
|
+
class InvokeResponseFactory {
|
|
2070
|
+
/**
|
|
2071
|
+
* Create an invoke response from a text message.
|
|
2072
|
+
* The type of the invoke response is `application/vnd.microsoft.activity.message`
|
|
2073
|
+
* indicates the request was successfully processed.
|
|
2074
|
+
*
|
|
2075
|
+
* @param message A text message included in a invoke response.
|
|
2076
|
+
*
|
|
2077
|
+
* @returns {InvokeResponse} An InvokeResponse object.
|
|
2078
|
+
*/
|
|
2079
|
+
static textMessage(message) {
|
|
2080
|
+
if (!message) {
|
|
2081
|
+
throw new Error("The text message cannot be null or empty");
|
|
2082
|
+
}
|
|
2083
|
+
return {
|
|
2084
|
+
status: botbuilder.StatusCodes.OK,
|
|
2085
|
+
body: {
|
|
2086
|
+
statusCode: botbuilder.StatusCodes.OK,
|
|
2087
|
+
type: InvokeResponseType.Message,
|
|
2088
|
+
value: message,
|
|
2089
|
+
},
|
|
2090
|
+
};
|
|
1988
2091
|
}
|
|
1989
|
-
|
|
1990
|
-
|
|
2092
|
+
/**
|
|
2093
|
+
* Create an invoke response from an adaptive card.
|
|
2094
|
+
*
|
|
2095
|
+
* The type of the invoke response is `application/vnd.microsoft.card.adaptive` indicates
|
|
2096
|
+
* the request was successfully processed, and the response includes an adaptive card
|
|
2097
|
+
* that the client should display in place of the current one.
|
|
2098
|
+
*
|
|
2099
|
+
* @param card The adaptive card JSON payload.
|
|
2100
|
+
*
|
|
2101
|
+
* @returns {InvokeResponse} An InvokeResponse object.
|
|
2102
|
+
*/
|
|
2103
|
+
static adaptiveCard(card) {
|
|
2104
|
+
if (!card) {
|
|
2105
|
+
throw new Error("The adaptive card content cannot be null or undefined");
|
|
2106
|
+
}
|
|
2107
|
+
return {
|
|
2108
|
+
status: botbuilder.StatusCodes.OK,
|
|
2109
|
+
body: {
|
|
2110
|
+
statusCode: botbuilder.StatusCodes.OK,
|
|
2111
|
+
type: InvokeResponseType.AdaptiveCard,
|
|
2112
|
+
value: card,
|
|
2113
|
+
},
|
|
2114
|
+
};
|
|
1991
2115
|
}
|
|
1992
|
-
|
|
1993
|
-
|
|
2116
|
+
/**
|
|
2117
|
+
* Create an invoke response with error code and message.
|
|
2118
|
+
*
|
|
2119
|
+
* The type of the invoke response is `application/vnd.microsoft.error` indicates
|
|
2120
|
+
* the request was failed to processed.
|
|
2121
|
+
*
|
|
2122
|
+
* @param errorCode The status code indicates error, available values:
|
|
2123
|
+
* - 400 (BadRequest): indicate the incoming request was invalid.
|
|
2124
|
+
* - 500 (InternalServerError): indicate an unexpected error occurred.
|
|
2125
|
+
* @param errorMessage The error message.
|
|
2126
|
+
*
|
|
2127
|
+
* @returns {InvokeResponse} An InvokeResponse object.
|
|
2128
|
+
*/
|
|
2129
|
+
static errorResponse(errorCode, errorMessage) {
|
|
2130
|
+
return {
|
|
2131
|
+
status: botbuilder.StatusCodes.OK,
|
|
2132
|
+
body: {
|
|
2133
|
+
statusCode: errorCode,
|
|
2134
|
+
type: InvokeResponseType.Error,
|
|
2135
|
+
value: {
|
|
2136
|
+
code: errorCode.toString(),
|
|
2137
|
+
message: errorMessage,
|
|
2138
|
+
},
|
|
2139
|
+
},
|
|
2140
|
+
};
|
|
1994
2141
|
}
|
|
1995
|
-
|
|
1996
|
-
|
|
2142
|
+
/**
|
|
2143
|
+
* Create an invoke response with status code and response value.
|
|
2144
|
+
* @param statusCode The status code.
|
|
2145
|
+
* @param body The value of the response body.
|
|
2146
|
+
*
|
|
2147
|
+
* @returns {InvokeResponse} An InvokeResponse object.
|
|
2148
|
+
*/
|
|
2149
|
+
static createInvokeResponse(statusCode, body) {
|
|
2150
|
+
return {
|
|
2151
|
+
status: statusCode,
|
|
2152
|
+
body: body,
|
|
2153
|
+
};
|
|
1997
2154
|
}
|
|
1998
|
-
}
|
|
1999
|
-
/**
|
|
2000
|
-
* @internal
|
|
2001
|
-
*/
|
|
2002
|
-
function getTeamsBotInstallationId(context) {
|
|
2003
|
-
var _a, _b, _c, _d;
|
|
2004
|
-
return (_d = (_c = (_b = (_a = context.activity) === null || _a === void 0 ? void 0 : _a.channelData) === null || _b === void 0 ? void 0 : _b.team) === null || _c === void 0 ? void 0 : _c.id) !== null && _d !== void 0 ? _d : context.activity.conversation.id;
|
|
2005
2155
|
}
|
|
2006
2156
|
|
|
2007
|
-
// Copyright (c) Microsoft Corporation.
|
|
2008
|
-
/**
|
|
2009
|
-
* @internal
|
|
2010
|
-
*/
|
|
2011
|
-
var ActivityType;
|
|
2012
|
-
(function (ActivityType) {
|
|
2013
|
-
ActivityType[ActivityType["CurrentBotInstalled"] = 0] = "CurrentBotInstalled";
|
|
2014
|
-
ActivityType[ActivityType["CurrentBotMessaged"] = 1] = "CurrentBotMessaged";
|
|
2015
|
-
ActivityType[ActivityType["CurrentBotUninstalled"] = 2] = "CurrentBotUninstalled";
|
|
2016
|
-
ActivityType[ActivityType["TeamDeleted"] = 3] = "TeamDeleted";
|
|
2017
|
-
ActivityType[ActivityType["TeamRestored"] = 4] = "TeamRestored";
|
|
2018
|
-
ActivityType[ActivityType["Unknown"] = 5] = "Unknown";
|
|
2019
|
-
})(ActivityType || (ActivityType = {}));
|
|
2020
2157
|
/**
|
|
2021
2158
|
* @internal
|
|
2022
2159
|
*/
|
|
2023
|
-
class
|
|
2024
|
-
constructor(
|
|
2025
|
-
this.
|
|
2160
|
+
class CardActionMiddleware {
|
|
2161
|
+
constructor(handlers) {
|
|
2162
|
+
this.actionHandlers = [];
|
|
2163
|
+
this.defaultMessage = "Your response was sent to the app";
|
|
2164
|
+
if (handlers && handlers.length > 0) {
|
|
2165
|
+
this.actionHandlers.push(...handlers);
|
|
2166
|
+
}
|
|
2026
2167
|
}
|
|
2027
2168
|
onTurn(context, next) {
|
|
2169
|
+
var _a, _b, _c;
|
|
2028
2170
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2171
|
+
if (context.activity.name === "adaptiveCard/action") {
|
|
2172
|
+
const action = context.activity.value.action;
|
|
2173
|
+
const actionVerb = action.verb;
|
|
2174
|
+
for (const handler of this.actionHandlers) {
|
|
2175
|
+
if (((_a = handler.triggerVerb) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === (actionVerb === null || actionVerb === void 0 ? void 0 : actionVerb.toLowerCase())) {
|
|
2176
|
+
let response;
|
|
2177
|
+
try {
|
|
2178
|
+
response = yield handler.handleActionInvoked(context, action.data);
|
|
2179
|
+
}
|
|
2180
|
+
catch (error) {
|
|
2181
|
+
const errorResponse = InvokeResponseFactory.errorResponse(exports.InvokeResponseErrorCode.InternalServerError, error.message);
|
|
2182
|
+
yield this.sendInvokeResponse(context, errorResponse);
|
|
2183
|
+
throw error;
|
|
2184
|
+
}
|
|
2185
|
+
const responseType = (_b = response.body) === null || _b === void 0 ? void 0 : _b.type;
|
|
2186
|
+
switch (responseType) {
|
|
2187
|
+
case InvokeResponseType.AdaptiveCard:
|
|
2188
|
+
const card = (_c = response.body) === null || _c === void 0 ? void 0 : _c.value;
|
|
2189
|
+
if (!card) {
|
|
2190
|
+
const errorMessage = "Adaptive card content cannot be found in the response body";
|
|
2191
|
+
yield this.sendInvokeResponse(context, InvokeResponseFactory.errorResponse(exports.InvokeResponseErrorCode.InternalServerError, errorMessage));
|
|
2192
|
+
throw new Error(errorMessage);
|
|
2193
|
+
}
|
|
2194
|
+
if (card.refresh && handler.adaptiveCardResponse !== exports.AdaptiveCardResponse.NewForAll) {
|
|
2195
|
+
// Card won't be refreshed with AdaptiveCardResponse.ReplaceForInteractor.
|
|
2196
|
+
// So set to AdaptiveCardResponse.ReplaceForAll here.
|
|
2197
|
+
handler.adaptiveCardResponse = exports.AdaptiveCardResponse.ReplaceForAll;
|
|
2198
|
+
}
|
|
2199
|
+
const activity = botbuilder.MessageFactory.attachment(botbuilder.CardFactory.adaptiveCard(card));
|
|
2200
|
+
if (handler.adaptiveCardResponse === exports.AdaptiveCardResponse.NewForAll) {
|
|
2201
|
+
yield this.sendInvokeResponse(context, InvokeResponseFactory.textMessage(this.defaultMessage));
|
|
2202
|
+
yield context.sendActivity(activity);
|
|
2203
|
+
}
|
|
2204
|
+
else if (handler.adaptiveCardResponse === exports.AdaptiveCardResponse.ReplaceForAll) {
|
|
2205
|
+
activity.id = context.activity.replyToId;
|
|
2206
|
+
yield context.updateActivity(activity);
|
|
2207
|
+
yield this.sendInvokeResponse(context, response);
|
|
2208
|
+
}
|
|
2209
|
+
else {
|
|
2210
|
+
yield this.sendInvokeResponse(context, response);
|
|
2211
|
+
}
|
|
2212
|
+
break;
|
|
2213
|
+
case InvokeResponseType.Message:
|
|
2214
|
+
case InvokeResponseType.Error:
|
|
2215
|
+
default:
|
|
2216
|
+
yield this.sendInvokeResponse(context, response);
|
|
2217
|
+
break;
|
|
2218
|
+
}
|
|
2219
|
+
break;
|
|
2220
|
+
}
|
|
2046
2221
|
}
|
|
2047
2222
|
}
|
|
2048
2223
|
yield next();
|
|
2049
2224
|
});
|
|
2050
2225
|
}
|
|
2051
|
-
|
|
2052
|
-
var _a, _b;
|
|
2053
|
-
const activityType = activity.type;
|
|
2054
|
-
if (activityType === "installationUpdate") {
|
|
2055
|
-
const action = (_a = activity.action) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
2056
|
-
if (action === "add") {
|
|
2057
|
-
return ActivityType.CurrentBotInstalled;
|
|
2058
|
-
}
|
|
2059
|
-
else {
|
|
2060
|
-
return ActivityType.CurrentBotUninstalled;
|
|
2061
|
-
}
|
|
2062
|
-
}
|
|
2063
|
-
else if (activityType === "conversationUpdate") {
|
|
2064
|
-
const eventType = (_b = activity.channelData) === null || _b === void 0 ? void 0 : _b.eventType;
|
|
2065
|
-
if (eventType === "teamDeleted") {
|
|
2066
|
-
return ActivityType.TeamDeleted;
|
|
2067
|
-
}
|
|
2068
|
-
else if (eventType === "teamRestored") {
|
|
2069
|
-
return ActivityType.TeamRestored;
|
|
2070
|
-
}
|
|
2071
|
-
}
|
|
2072
|
-
else if (activityType === "message") {
|
|
2073
|
-
return ActivityType.CurrentBotMessaged;
|
|
2074
|
-
}
|
|
2075
|
-
return ActivityType.Unknown;
|
|
2076
|
-
}
|
|
2077
|
-
tryAddMessagedReference(context) {
|
|
2078
|
-
var _a, _b, _c, _d;
|
|
2226
|
+
sendInvokeResponse(context, response) {
|
|
2079
2227
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
yield this.conversationReferenceStore.set(reference);
|
|
2085
|
-
}
|
|
2086
|
-
}
|
|
2087
|
-
else if (conversationType === "channel") {
|
|
2088
|
-
const teamId = (_d = (_c = (_b = context.activity) === null || _b === void 0 ? void 0 : _b.channelData) === null || _c === void 0 ? void 0 : _c.team) === null || _d === void 0 ? void 0 : _d.id;
|
|
2089
|
-
if (teamId !== undefined) {
|
|
2090
|
-
const teamReference = cloneConversation(reference);
|
|
2091
|
-
teamReference.conversation.id = teamId;
|
|
2092
|
-
if (!(yield this.conversationReferenceStore.check(teamReference))) {
|
|
2093
|
-
yield this.conversationReferenceStore.set(teamReference);
|
|
2094
|
-
}
|
|
2095
|
-
}
|
|
2096
|
-
}
|
|
2228
|
+
yield context.sendActivity({
|
|
2229
|
+
type: botbuilder.ActivityTypes.InvokeResponse,
|
|
2230
|
+
value: response,
|
|
2231
|
+
});
|
|
2097
2232
|
});
|
|
2098
2233
|
}
|
|
2099
|
-
}
|
|
2234
|
+
}
|
|
2235
|
+
|
|
2236
|
+
/**
|
|
2237
|
+
* A card action bot to respond to adaptive card universal actions.
|
|
2238
|
+
*/
|
|
2239
|
+
class CardActionBot {
|
|
2240
|
+
/**
|
|
2241
|
+
* Creates a new instance of the `CardActionBot`.
|
|
2242
|
+
*
|
|
2243
|
+
* @param adapter The bound `BotFrameworkAdapter`.
|
|
2244
|
+
* @param options - initialize options
|
|
2245
|
+
*/
|
|
2246
|
+
constructor(adapter, options) {
|
|
2247
|
+
this.middleware = new CardActionMiddleware(options === null || options === void 0 ? void 0 : options.actions);
|
|
2248
|
+
this.adapter = adapter.use(this.middleware);
|
|
2249
|
+
}
|
|
2250
|
+
/**
|
|
2251
|
+
* Registers a card action handler to the bot.
|
|
2252
|
+
* @param actionHandler A card action handler to be registered.
|
|
2253
|
+
*/
|
|
2254
|
+
registerHandler(actionHandler) {
|
|
2255
|
+
if (actionHandler) {
|
|
2256
|
+
this.middleware.actionHandlers.push(actionHandler);
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
/**
|
|
2260
|
+
* Registers card action handlers to the bot.
|
|
2261
|
+
* @param actionHandlers A set of card action handlers to be registered.
|
|
2262
|
+
*/
|
|
2263
|
+
registerHandlers(actionHandlers) {
|
|
2264
|
+
if (actionHandlers) {
|
|
2265
|
+
this.middleware.actionHandlers.push(...actionHandlers);
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2268
|
+
}
|
|
2269
|
+
|
|
2270
|
+
// Copyright (c) Microsoft Corporation.
|
|
2271
|
+
/**
|
|
2272
|
+
* @internal
|
|
2273
|
+
*/
|
|
2100
2274
|
class CommandResponseMiddleware {
|
|
2101
|
-
constructor(handlers) {
|
|
2275
|
+
constructor(handlers, ssoHandlers, activityHandler) {
|
|
2102
2276
|
this.commandHandlers = [];
|
|
2103
|
-
|
|
2104
|
-
|
|
2277
|
+
this.ssoCommandHandlers = [];
|
|
2278
|
+
handlers = handlers !== null && handlers !== void 0 ? handlers : [];
|
|
2279
|
+
ssoHandlers = ssoHandlers !== null && ssoHandlers !== void 0 ? ssoHandlers : [];
|
|
2280
|
+
this.hasSsoCommand = ssoHandlers.length > 0;
|
|
2281
|
+
this.ssoActivityHandler = activityHandler;
|
|
2282
|
+
if (this.hasSsoCommand && !this.ssoActivityHandler) {
|
|
2283
|
+
internalLogger.error(ErrorMessage.SsoActivityHandlerIsNull);
|
|
2284
|
+
throw new ErrorWithCode(ErrorMessage.SsoActivityHandlerIsNull, exports.ErrorCode.SsoActivityHandlerIsUndefined);
|
|
2285
|
+
}
|
|
2286
|
+
this.commandHandlers.push(...handlers);
|
|
2287
|
+
for (const ssoHandler of ssoHandlers) {
|
|
2288
|
+
this.addSsoCommand(ssoHandler);
|
|
2105
2289
|
}
|
|
2106
2290
|
}
|
|
2291
|
+
addSsoCommand(ssoHandler) {
|
|
2292
|
+
var _a;
|
|
2293
|
+
(_a = this.ssoActivityHandler) === null || _a === void 0 ? void 0 : _a.addCommand((context, tokenResponse, message) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2294
|
+
const matchResult = this.shouldTrigger(ssoHandler.triggerPatterns, message.text);
|
|
2295
|
+
message.matches = Array.isArray(matchResult) ? matchResult : void 0;
|
|
2296
|
+
const response = yield ssoHandler.handleCommandReceived(context, message, tokenResponse);
|
|
2297
|
+
yield this.processResponse(context, response);
|
|
2298
|
+
}), ssoHandler.triggerPatterns);
|
|
2299
|
+
this.ssoCommandHandlers.push(ssoHandler);
|
|
2300
|
+
this.hasSsoCommand = true;
|
|
2301
|
+
}
|
|
2107
2302
|
onTurn(context, next) {
|
|
2303
|
+
var _a, _b;
|
|
2108
2304
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2109
2305
|
if (context.activity.type === botbuilder.ActivityTypes.Message) {
|
|
2110
2306
|
// Invoke corresponding command handler for the command response
|
|
2111
2307
|
const commandText = this.getActivityText(context.activity);
|
|
2112
|
-
|
|
2113
|
-
text: commandText,
|
|
2114
|
-
};
|
|
2308
|
+
let alreadyProcessed = false;
|
|
2115
2309
|
for (const handler of this.commandHandlers) {
|
|
2116
2310
|
const matchResult = this.shouldTrigger(handler.triggerPatterns, commandText);
|
|
2117
2311
|
// It is important to note that the command bot will stop processing handlers
|
|
2118
2312
|
// when the first command handler is matched.
|
|
2119
2313
|
if (!!matchResult) {
|
|
2314
|
+
const message = {
|
|
2315
|
+
text: commandText,
|
|
2316
|
+
};
|
|
2120
2317
|
message.matches = Array.isArray(matchResult) ? matchResult : void 0;
|
|
2121
2318
|
const response = yield handler.handleCommandReceived(context, message);
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2319
|
+
yield this.processResponse(context, response);
|
|
2320
|
+
alreadyProcessed = true;
|
|
2321
|
+
break;
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2324
|
+
if (!alreadyProcessed) {
|
|
2325
|
+
for (const handler of this.ssoCommandHandlers) {
|
|
2326
|
+
const matchResult = this.shouldTrigger(handler.triggerPatterns, commandText);
|
|
2327
|
+
if (!!matchResult) {
|
|
2328
|
+
yield ((_a = this.ssoActivityHandler) === null || _a === void 0 ? void 0 : _a.run(context));
|
|
2329
|
+
break;
|
|
2130
2330
|
}
|
|
2131
2331
|
}
|
|
2132
2332
|
}
|
|
2133
2333
|
}
|
|
2334
|
+
else {
|
|
2335
|
+
if (this.hasSsoCommand) {
|
|
2336
|
+
yield ((_b = this.ssoActivityHandler) === null || _b === void 0 ? void 0 : _b.run(context));
|
|
2337
|
+
}
|
|
2338
|
+
}
|
|
2134
2339
|
yield next();
|
|
2135
2340
|
});
|
|
2136
2341
|
}
|
|
2342
|
+
processResponse(context, response) {
|
|
2343
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2344
|
+
if (typeof response === "string") {
|
|
2345
|
+
yield context.sendActivity(response);
|
|
2346
|
+
}
|
|
2347
|
+
else {
|
|
2348
|
+
const replyActivity = response;
|
|
2349
|
+
if (replyActivity) {
|
|
2350
|
+
yield context.sendActivity(replyActivity);
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2353
|
+
});
|
|
2354
|
+
}
|
|
2137
2355
|
matchPattern(pattern, text) {
|
|
2138
2356
|
if (text) {
|
|
2139
2357
|
if (typeof pattern === "string") {
|
|
@@ -2175,8 +2393,6 @@ class CommandResponseMiddleware {
|
|
|
2175
2393
|
*
|
|
2176
2394
|
* @remarks
|
|
2177
2395
|
* Ensure each command should ONLY be registered with the command once, otherwise it'll cause unexpected behavior if you register the same command more than once.
|
|
2178
|
-
*
|
|
2179
|
-
* @beta
|
|
2180
2396
|
*/
|
|
2181
2397
|
class CommandBot {
|
|
2182
2398
|
/**
|
|
@@ -2184,19 +2400,16 @@ class CommandBot {
|
|
|
2184
2400
|
*
|
|
2185
2401
|
* @param adapter The bound `BotFrameworkAdapter`.
|
|
2186
2402
|
* @param options - initialize options
|
|
2187
|
-
*
|
|
2188
|
-
* @beta
|
|
2189
2403
|
*/
|
|
2190
|
-
constructor(adapter, options) {
|
|
2191
|
-
this.
|
|
2404
|
+
constructor(adapter, options, ssoCommandActivityHandler, ssoConfig) {
|
|
2405
|
+
this.ssoConfig = ssoConfig;
|
|
2406
|
+
this.middleware = new CommandResponseMiddleware(options === null || options === void 0 ? void 0 : options.commands, options === null || options === void 0 ? void 0 : options.ssoCommands, ssoCommandActivityHandler);
|
|
2192
2407
|
this.adapter = adapter.use(this.middleware);
|
|
2193
2408
|
}
|
|
2194
2409
|
/**
|
|
2195
2410
|
* Registers a command into the command bot.
|
|
2196
2411
|
*
|
|
2197
|
-
* @param command The command to
|
|
2198
|
-
*
|
|
2199
|
-
* @beta
|
|
2412
|
+
* @param command The command to register.
|
|
2200
2413
|
*/
|
|
2201
2414
|
registerCommand(command) {
|
|
2202
2415
|
if (command) {
|
|
@@ -2206,15 +2419,178 @@ class CommandBot {
|
|
|
2206
2419
|
/**
|
|
2207
2420
|
* Registers commands into the command bot.
|
|
2208
2421
|
*
|
|
2209
|
-
* @param commands The
|
|
2210
|
-
*
|
|
2211
|
-
* @beta
|
|
2422
|
+
* @param commands The commands to register.
|
|
2212
2423
|
*/
|
|
2213
2424
|
registerCommands(commands) {
|
|
2214
2425
|
if (commands) {
|
|
2215
2426
|
this.middleware.commandHandlers.push(...commands);
|
|
2216
2427
|
}
|
|
2217
2428
|
}
|
|
2429
|
+
/**
|
|
2430
|
+
* Registers a sso command into the command bot.
|
|
2431
|
+
*
|
|
2432
|
+
* @param command The command to register.
|
|
2433
|
+
*/
|
|
2434
|
+
registerSsoCommand(ssoCommand) {
|
|
2435
|
+
this.validateSsoActivityHandler();
|
|
2436
|
+
this.middleware.addSsoCommand(ssoCommand);
|
|
2437
|
+
}
|
|
2438
|
+
/**
|
|
2439
|
+
* Registers commands into the command bot.
|
|
2440
|
+
*
|
|
2441
|
+
* @param commands The commands to register.
|
|
2442
|
+
*/
|
|
2443
|
+
registerSsoCommands(ssoCommands) {
|
|
2444
|
+
if (ssoCommands.length > 0) {
|
|
2445
|
+
this.validateSsoActivityHandler();
|
|
2446
|
+
for (const ssoCommand of ssoCommands) {
|
|
2447
|
+
this.middleware.addSsoCommand(ssoCommand);
|
|
2448
|
+
}
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2451
|
+
validateSsoActivityHandler() {
|
|
2452
|
+
if (!this.middleware.ssoActivityHandler) {
|
|
2453
|
+
internalLogger.error(ErrorMessage.SsoActivityHandlerIsNull);
|
|
2454
|
+
throw new ErrorWithCode(ErrorMessage.SsoActivityHandlerIsNull, exports.ErrorCode.SsoActivityHandlerIsUndefined);
|
|
2455
|
+
}
|
|
2456
|
+
}
|
|
2457
|
+
}
|
|
2458
|
+
|
|
2459
|
+
// Copyright (c) Microsoft Corporation.
|
|
2460
|
+
/**
|
|
2461
|
+
* @internal
|
|
2462
|
+
*/
|
|
2463
|
+
function cloneConversation(conversation) {
|
|
2464
|
+
return JSON.parse(JSON.stringify(conversation));
|
|
2465
|
+
}
|
|
2466
|
+
/**
|
|
2467
|
+
* @internal
|
|
2468
|
+
*/
|
|
2469
|
+
function getTargetType(conversationReference) {
|
|
2470
|
+
var _a;
|
|
2471
|
+
const conversationType = (_a = conversationReference.conversation) === null || _a === void 0 ? void 0 : _a.conversationType;
|
|
2472
|
+
if (conversationType === "personal") {
|
|
2473
|
+
return exports.NotificationTargetType.Person;
|
|
2474
|
+
}
|
|
2475
|
+
else if (conversationType === "groupChat") {
|
|
2476
|
+
return exports.NotificationTargetType.Group;
|
|
2477
|
+
}
|
|
2478
|
+
else if (conversationType === "channel") {
|
|
2479
|
+
return exports.NotificationTargetType.Channel;
|
|
2480
|
+
}
|
|
2481
|
+
else {
|
|
2482
|
+
return undefined;
|
|
2483
|
+
}
|
|
2484
|
+
}
|
|
2485
|
+
/**
|
|
2486
|
+
* @internal
|
|
2487
|
+
*/
|
|
2488
|
+
function getTeamsBotInstallationId(context) {
|
|
2489
|
+
var _a, _b, _c;
|
|
2490
|
+
const teamId = (_c = (_b = (_a = context.activity) === null || _a === void 0 ? void 0 : _a.channelData) === null || _b === void 0 ? void 0 : _b.team) === null || _c === void 0 ? void 0 : _c.id;
|
|
2491
|
+
if (teamId) {
|
|
2492
|
+
return teamId;
|
|
2493
|
+
}
|
|
2494
|
+
// Fallback to use conversation id.
|
|
2495
|
+
// the conversation id is equal to team id only when the bot app is installed into the General channel.
|
|
2496
|
+
if (context.activity.conversation.name === undefined) {
|
|
2497
|
+
return context.activity.conversation.id;
|
|
2498
|
+
}
|
|
2499
|
+
return undefined;
|
|
2500
|
+
}
|
|
2501
|
+
|
|
2502
|
+
// Copyright (c) Microsoft Corporation.
|
|
2503
|
+
/**
|
|
2504
|
+
* @internal
|
|
2505
|
+
*/
|
|
2506
|
+
var ActivityType;
|
|
2507
|
+
(function (ActivityType) {
|
|
2508
|
+
ActivityType[ActivityType["CurrentBotInstalled"] = 0] = "CurrentBotInstalled";
|
|
2509
|
+
ActivityType[ActivityType["CurrentBotMessaged"] = 1] = "CurrentBotMessaged";
|
|
2510
|
+
ActivityType[ActivityType["CurrentBotUninstalled"] = 2] = "CurrentBotUninstalled";
|
|
2511
|
+
ActivityType[ActivityType["TeamDeleted"] = 3] = "TeamDeleted";
|
|
2512
|
+
ActivityType[ActivityType["TeamRestored"] = 4] = "TeamRestored";
|
|
2513
|
+
ActivityType[ActivityType["Unknown"] = 5] = "Unknown";
|
|
2514
|
+
})(ActivityType || (ActivityType = {}));
|
|
2515
|
+
/**
|
|
2516
|
+
* @internal
|
|
2517
|
+
*/
|
|
2518
|
+
class NotificationMiddleware {
|
|
2519
|
+
constructor(options) {
|
|
2520
|
+
this.conversationReferenceStore = options.conversationReferenceStore;
|
|
2521
|
+
}
|
|
2522
|
+
onTurn(context, next) {
|
|
2523
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2524
|
+
const type = this.classifyActivity(context.activity);
|
|
2525
|
+
switch (type) {
|
|
2526
|
+
case ActivityType.CurrentBotInstalled:
|
|
2527
|
+
case ActivityType.TeamRestored: {
|
|
2528
|
+
const reference = botbuilder.TurnContext.getConversationReference(context.activity);
|
|
2529
|
+
yield this.conversationReferenceStore.set(reference);
|
|
2530
|
+
break;
|
|
2531
|
+
}
|
|
2532
|
+
case ActivityType.CurrentBotMessaged: {
|
|
2533
|
+
yield this.tryAddMessagedReference(context);
|
|
2534
|
+
break;
|
|
2535
|
+
}
|
|
2536
|
+
case ActivityType.CurrentBotUninstalled:
|
|
2537
|
+
case ActivityType.TeamDeleted: {
|
|
2538
|
+
const reference = botbuilder.TurnContext.getConversationReference(context.activity);
|
|
2539
|
+
yield this.conversationReferenceStore.delete(reference);
|
|
2540
|
+
break;
|
|
2541
|
+
}
|
|
2542
|
+
}
|
|
2543
|
+
yield next();
|
|
2544
|
+
});
|
|
2545
|
+
}
|
|
2546
|
+
classifyActivity(activity) {
|
|
2547
|
+
var _a, _b;
|
|
2548
|
+
const activityType = activity.type;
|
|
2549
|
+
if (activityType === "installationUpdate") {
|
|
2550
|
+
const action = (_a = activity.action) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
2551
|
+
if (action === "add") {
|
|
2552
|
+
return ActivityType.CurrentBotInstalled;
|
|
2553
|
+
}
|
|
2554
|
+
else {
|
|
2555
|
+
return ActivityType.CurrentBotUninstalled;
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2558
|
+
else if (activityType === "conversationUpdate") {
|
|
2559
|
+
const eventType = (_b = activity.channelData) === null || _b === void 0 ? void 0 : _b.eventType;
|
|
2560
|
+
if (eventType === "teamDeleted") {
|
|
2561
|
+
return ActivityType.TeamDeleted;
|
|
2562
|
+
}
|
|
2563
|
+
else if (eventType === "teamRestored") {
|
|
2564
|
+
return ActivityType.TeamRestored;
|
|
2565
|
+
}
|
|
2566
|
+
}
|
|
2567
|
+
else if (activityType === "message") {
|
|
2568
|
+
return ActivityType.CurrentBotMessaged;
|
|
2569
|
+
}
|
|
2570
|
+
return ActivityType.Unknown;
|
|
2571
|
+
}
|
|
2572
|
+
tryAddMessagedReference(context) {
|
|
2573
|
+
var _a, _b, _c, _d;
|
|
2574
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2575
|
+
const reference = botbuilder.TurnContext.getConversationReference(context.activity);
|
|
2576
|
+
const conversationType = (_a = reference === null || reference === void 0 ? void 0 : reference.conversation) === null || _a === void 0 ? void 0 : _a.conversationType;
|
|
2577
|
+
if (conversationType === "personal" || conversationType === "groupChat") {
|
|
2578
|
+
if (!(yield this.conversationReferenceStore.check(reference))) {
|
|
2579
|
+
yield this.conversationReferenceStore.set(reference);
|
|
2580
|
+
}
|
|
2581
|
+
}
|
|
2582
|
+
else if (conversationType === "channel") {
|
|
2583
|
+
const teamId = (_d = (_c = (_b = context.activity) === null || _b === void 0 ? void 0 : _b.channelData) === null || _c === void 0 ? void 0 : _c.team) === null || _d === void 0 ? void 0 : _d.id;
|
|
2584
|
+
if (teamId !== undefined) {
|
|
2585
|
+
const teamReference = cloneConversation(reference);
|
|
2586
|
+
teamReference.conversation.id = teamId;
|
|
2587
|
+
if (!(yield this.conversationReferenceStore.check(teamReference))) {
|
|
2588
|
+
yield this.conversationReferenceStore.set(teamReference);
|
|
2589
|
+
}
|
|
2590
|
+
}
|
|
2591
|
+
}
|
|
2592
|
+
});
|
|
2593
|
+
}
|
|
2218
2594
|
}
|
|
2219
2595
|
|
|
2220
2596
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -2354,32 +2730,30 @@ class ConversationReferenceStore {
|
|
|
2354
2730
|
*
|
|
2355
2731
|
* @param target - the notification target.
|
|
2356
2732
|
* @param text - the plain text message.
|
|
2357
|
-
* @
|
|
2358
|
-
*
|
|
2359
|
-
* @
|
|
2733
|
+
* @param onError - an optional error handler that can catch exceptions during message sending.
|
|
2734
|
+
* If not defined, error will be handled by `BotAdapter.onTurnError`.
|
|
2735
|
+
* @returns the response of sending message.
|
|
2360
2736
|
*/
|
|
2361
|
-
function sendMessage(target, text) {
|
|
2362
|
-
return target.sendMessage(text);
|
|
2737
|
+
function sendMessage(target, text, onError) {
|
|
2738
|
+
return target.sendMessage(text, onError);
|
|
2363
2739
|
}
|
|
2364
2740
|
/**
|
|
2365
2741
|
* Send an adaptive card message to a notification target.
|
|
2366
2742
|
*
|
|
2367
2743
|
* @param target - the notification target.
|
|
2368
2744
|
* @param card - the adaptive card raw JSON.
|
|
2369
|
-
* @
|
|
2370
|
-
*
|
|
2371
|
-
* @
|
|
2745
|
+
* @param onError - an optional error handler that can catch exceptions during adaptive card sending.
|
|
2746
|
+
* If not defined, error will be handled by `BotAdapter.onTurnError`.
|
|
2747
|
+
* @returns the response of sending adaptive card message.
|
|
2372
2748
|
*/
|
|
2373
|
-
function sendAdaptiveCard(target, card) {
|
|
2374
|
-
return target.sendAdaptiveCard(card);
|
|
2749
|
+
function sendAdaptiveCard(target, card, onError) {
|
|
2750
|
+
return target.sendAdaptiveCard(card, onError);
|
|
2375
2751
|
}
|
|
2376
2752
|
/**
|
|
2377
2753
|
* A {@link NotificationTarget} that represents a team channel.
|
|
2378
2754
|
*
|
|
2379
2755
|
* @remarks
|
|
2380
2756
|
* It's recommended to get channels from {@link TeamsBotInstallation.channels()}.
|
|
2381
|
-
*
|
|
2382
|
-
* @beta
|
|
2383
2757
|
*/
|
|
2384
2758
|
class Channel {
|
|
2385
2759
|
/**
|
|
@@ -2390,16 +2764,12 @@ class Channel {
|
|
|
2390
2764
|
*
|
|
2391
2765
|
* @param parent - The parent {@link TeamsBotInstallation} where this channel is created from.
|
|
2392
2766
|
* @param info - Detailed channel information.
|
|
2393
|
-
*
|
|
2394
|
-
* @beta
|
|
2395
2767
|
*/
|
|
2396
2768
|
constructor(parent, info) {
|
|
2397
2769
|
/**
|
|
2398
2770
|
* Notification target type. For channel it's always "Channel".
|
|
2399
|
-
*
|
|
2400
|
-
* @beta
|
|
2401
2771
|
*/
|
|
2402
|
-
this.type =
|
|
2772
|
+
this.type = exports.NotificationTargetType.Channel;
|
|
2403
2773
|
this.parent = parent;
|
|
2404
2774
|
this.info = info;
|
|
2405
2775
|
}
|
|
@@ -2407,36 +2777,64 @@ class Channel {
|
|
|
2407
2777
|
* Send a plain text message.
|
|
2408
2778
|
*
|
|
2409
2779
|
* @param text - the plain text message.
|
|
2410
|
-
* @
|
|
2411
|
-
*
|
|
2412
|
-
* @
|
|
2780
|
+
* @param onError - an optional error handler that can catch exceptions during message sending.
|
|
2781
|
+
* If not defined, error will be handled by `BotAdapter.onTurnError`.
|
|
2782
|
+
* @returns the response of sending message.
|
|
2413
2783
|
*/
|
|
2414
|
-
sendMessage(text) {
|
|
2415
|
-
return
|
|
2416
|
-
const
|
|
2417
|
-
yield this.parent.adapter.continueConversation(
|
|
2418
|
-
yield
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2784
|
+
sendMessage(text, onError) {
|
|
2785
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2786
|
+
const response = {};
|
|
2787
|
+
yield this.parent.adapter.continueConversation(this.parent.conversationReference, (context) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2788
|
+
const conversation = yield this.newConversation(context);
|
|
2789
|
+
yield this.parent.adapter.continueConversation(conversation, (ctx) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2790
|
+
try {
|
|
2791
|
+
const res = yield ctx.sendActivity(text);
|
|
2792
|
+
response.id = res === null || res === void 0 ? void 0 : res.id;
|
|
2793
|
+
}
|
|
2794
|
+
catch (error) {
|
|
2795
|
+
if (onError) {
|
|
2796
|
+
yield onError(ctx, error);
|
|
2797
|
+
}
|
|
2798
|
+
else {
|
|
2799
|
+
throw error;
|
|
2800
|
+
}
|
|
2801
|
+
}
|
|
2802
|
+
}));
|
|
2803
|
+
}));
|
|
2804
|
+
return response;
|
|
2805
|
+
});
|
|
2806
|
+
}
|
|
2807
|
+
/**
|
|
2808
|
+
* Send an adaptive card message.
|
|
2427
2809
|
*
|
|
2428
|
-
* @
|
|
2810
|
+
* @param card - the adaptive card raw JSON.
|
|
2811
|
+
* @param onError - an optional error handler that can catch exceptions during adaptive card sending.
|
|
2812
|
+
* If not defined, error will be handled by `BotAdapter.onTurnError`.
|
|
2813
|
+
* @returns the response of sending adaptive card message.
|
|
2429
2814
|
*/
|
|
2430
|
-
sendAdaptiveCard(card) {
|
|
2815
|
+
sendAdaptiveCard(card, onError) {
|
|
2431
2816
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2432
|
-
|
|
2817
|
+
const response = {};
|
|
2818
|
+
yield this.parent.adapter.continueConversation(this.parent.conversationReference, (context) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2433
2819
|
const conversation = yield this.newConversation(context);
|
|
2434
2820
|
yield this.parent.adapter.continueConversation(conversation, (ctx) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2821
|
+
try {
|
|
2822
|
+
const res = yield ctx.sendActivity({
|
|
2823
|
+
attachments: [botbuilder.CardFactory.adaptiveCard(card)],
|
|
2824
|
+
});
|
|
2825
|
+
response.id = res === null || res === void 0 ? void 0 : res.id;
|
|
2826
|
+
}
|
|
2827
|
+
catch (error) {
|
|
2828
|
+
if (onError) {
|
|
2829
|
+
yield onError(ctx, error);
|
|
2830
|
+
}
|
|
2831
|
+
else {
|
|
2832
|
+
throw error;
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2438
2835
|
}));
|
|
2439
2836
|
}));
|
|
2837
|
+
return response;
|
|
2440
2838
|
});
|
|
2441
2839
|
}
|
|
2442
2840
|
/**
|
|
@@ -2456,8 +2854,6 @@ class Channel {
|
|
|
2456
2854
|
*
|
|
2457
2855
|
* @remarks
|
|
2458
2856
|
* It's recommended to get members from {@link TeamsBotInstallation.members()}.
|
|
2459
|
-
*
|
|
2460
|
-
* @beta
|
|
2461
2857
|
*/
|
|
2462
2858
|
class Member {
|
|
2463
2859
|
/**
|
|
@@ -2468,16 +2864,12 @@ class Member {
|
|
|
2468
2864
|
*
|
|
2469
2865
|
* @param parent - The parent {@link TeamsBotInstallation} where this member is created from.
|
|
2470
2866
|
* @param account - Detailed member account information.
|
|
2471
|
-
*
|
|
2472
|
-
* @beta
|
|
2473
2867
|
*/
|
|
2474
2868
|
constructor(parent, account) {
|
|
2475
2869
|
/**
|
|
2476
2870
|
* Notification target type. For member it's always "Person".
|
|
2477
|
-
*
|
|
2478
|
-
* @beta
|
|
2479
2871
|
*/
|
|
2480
|
-
this.type =
|
|
2872
|
+
this.type = exports.NotificationTargetType.Person;
|
|
2481
2873
|
this.parent = parent;
|
|
2482
2874
|
this.account = account;
|
|
2483
2875
|
}
|
|
@@ -2485,225 +2877,778 @@ class Member {
|
|
|
2485
2877
|
* Send a plain text message.
|
|
2486
2878
|
*
|
|
2487
2879
|
* @param text - the plain text message.
|
|
2488
|
-
* @
|
|
2489
|
-
*
|
|
2490
|
-
* @
|
|
2880
|
+
* @param onError - an optional error handler that can catch exceptions during message sending.
|
|
2881
|
+
* If not defined, error will be handled by `BotAdapter.onTurnError`.
|
|
2882
|
+
* @returns the response of sending message.
|
|
2491
2883
|
*/
|
|
2492
|
-
sendMessage(text) {
|
|
2493
|
-
return
|
|
2494
|
-
const
|
|
2495
|
-
yield this.parent.adapter.continueConversation(
|
|
2496
|
-
yield
|
|
2884
|
+
sendMessage(text, onError) {
|
|
2885
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2886
|
+
const response = {};
|
|
2887
|
+
yield this.parent.adapter.continueConversation(this.parent.conversationReference, (context) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2888
|
+
const conversation = yield this.newConversation(context);
|
|
2889
|
+
yield this.parent.adapter.continueConversation(conversation, (ctx) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2890
|
+
try {
|
|
2891
|
+
const res = yield ctx.sendActivity(text);
|
|
2892
|
+
response.id = res === null || res === void 0 ? void 0 : res.id;
|
|
2893
|
+
}
|
|
2894
|
+
catch (error) {
|
|
2895
|
+
if (onError) {
|
|
2896
|
+
yield onError(ctx, error);
|
|
2897
|
+
}
|
|
2898
|
+
else {
|
|
2899
|
+
throw error;
|
|
2900
|
+
}
|
|
2901
|
+
}
|
|
2902
|
+
}));
|
|
2497
2903
|
}));
|
|
2498
|
-
|
|
2904
|
+
return response;
|
|
2905
|
+
});
|
|
2499
2906
|
}
|
|
2500
2907
|
/**
|
|
2501
2908
|
* Send an adaptive card message.
|
|
2502
2909
|
*
|
|
2503
2910
|
* @param card - the adaptive card raw JSON.
|
|
2504
|
-
* @
|
|
2505
|
-
*
|
|
2506
|
-
* @
|
|
2911
|
+
* @param onError - an optional error handler that can catch exceptions during adaptive card sending.
|
|
2912
|
+
* If not defined, error will be handled by `BotAdapter.onTurnError`.
|
|
2913
|
+
* @returns the response of sending adaptive card message.
|
|
2507
2914
|
*/
|
|
2508
|
-
sendAdaptiveCard(card) {
|
|
2915
|
+
sendAdaptiveCard(card, onError) {
|
|
2509
2916
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2510
|
-
|
|
2917
|
+
const response = {};
|
|
2918
|
+
yield this.parent.adapter.continueConversation(this.parent.conversationReference, (context) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2511
2919
|
const conversation = yield this.newConversation(context);
|
|
2512
2920
|
yield this.parent.adapter.continueConversation(conversation, (ctx) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2513
|
-
|
|
2921
|
+
try {
|
|
2922
|
+
const res = yield ctx.sendActivity({
|
|
2923
|
+
attachments: [botbuilder.CardFactory.adaptiveCard(card)],
|
|
2924
|
+
});
|
|
2925
|
+
response.id = res === null || res === void 0 ? void 0 : res.id;
|
|
2926
|
+
}
|
|
2927
|
+
catch (error) {
|
|
2928
|
+
if (onError) {
|
|
2929
|
+
yield onError(ctx, error);
|
|
2930
|
+
}
|
|
2931
|
+
else {
|
|
2932
|
+
throw error;
|
|
2933
|
+
}
|
|
2934
|
+
}
|
|
2935
|
+
}));
|
|
2936
|
+
}));
|
|
2937
|
+
return response;
|
|
2938
|
+
});
|
|
2939
|
+
}
|
|
2940
|
+
/**
|
|
2941
|
+
* @internal
|
|
2942
|
+
*/
|
|
2943
|
+
newConversation(context) {
|
|
2944
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2945
|
+
const reference = botbuilder.TurnContext.getConversationReference(context.activity);
|
|
2946
|
+
const personalConversation = cloneConversation(reference);
|
|
2947
|
+
const connectorClient = context.turnState.get(this.parent.adapter.ConnectorClientKey);
|
|
2948
|
+
const conversation = yield connectorClient.conversations.createConversation({
|
|
2949
|
+
isGroup: false,
|
|
2950
|
+
tenantId: context.activity.conversation.tenantId,
|
|
2951
|
+
bot: context.activity.recipient,
|
|
2952
|
+
members: [this.account],
|
|
2953
|
+
channelData: {},
|
|
2954
|
+
});
|
|
2955
|
+
personalConversation.conversation.id = conversation.id;
|
|
2956
|
+
return personalConversation;
|
|
2957
|
+
});
|
|
2958
|
+
}
|
|
2959
|
+
}
|
|
2960
|
+
/**
|
|
2961
|
+
* A {@link NotificationTarget} that represents a bot installation. Teams Bot could be installed into
|
|
2962
|
+
* - Personal chat
|
|
2963
|
+
* - Group chat
|
|
2964
|
+
* - Team (by default the `General` channel)
|
|
2965
|
+
*
|
|
2966
|
+
* @remarks
|
|
2967
|
+
* It's recommended to get bot installations from {@link ConversationBot.installations()}.
|
|
2968
|
+
*/
|
|
2969
|
+
class TeamsBotInstallation {
|
|
2970
|
+
/**
|
|
2971
|
+
* Constructor
|
|
2972
|
+
*
|
|
2973
|
+
* @remarks
|
|
2974
|
+
* It's recommended to get bot installations from {@link ConversationBot.installations()}, instead of using this constructor.
|
|
2975
|
+
*
|
|
2976
|
+
* @param adapter - the bound `BotFrameworkAdapter`.
|
|
2977
|
+
* @param conversationReference - the bound `ConversationReference`.
|
|
2978
|
+
*/
|
|
2979
|
+
constructor(adapter, conversationReference) {
|
|
2980
|
+
this.adapter = adapter;
|
|
2981
|
+
this.conversationReference = conversationReference;
|
|
2982
|
+
this.type = getTargetType(conversationReference);
|
|
2983
|
+
}
|
|
2984
|
+
/**
|
|
2985
|
+
* Send a plain text message.
|
|
2986
|
+
*
|
|
2987
|
+
* @param text - the plain text message.
|
|
2988
|
+
* @param onError - an optional error handler that can catch exceptions during message sending.
|
|
2989
|
+
* If not defined, error will be handled by `BotAdapter.onTurnError`.
|
|
2990
|
+
* @returns the response of sending message.
|
|
2991
|
+
*/
|
|
2992
|
+
sendMessage(text, onError) {
|
|
2993
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2994
|
+
const response = {};
|
|
2995
|
+
yield this.adapter.continueConversation(this.conversationReference, (context) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2996
|
+
try {
|
|
2997
|
+
const res = yield context.sendActivity(text);
|
|
2998
|
+
response.id = res === null || res === void 0 ? void 0 : res.id;
|
|
2999
|
+
}
|
|
3000
|
+
catch (error) {
|
|
3001
|
+
if (onError) {
|
|
3002
|
+
yield onError(context, error);
|
|
3003
|
+
}
|
|
3004
|
+
else {
|
|
3005
|
+
throw error;
|
|
3006
|
+
}
|
|
3007
|
+
}
|
|
3008
|
+
}));
|
|
3009
|
+
return response;
|
|
3010
|
+
});
|
|
3011
|
+
}
|
|
3012
|
+
/**
|
|
3013
|
+
* Send an adaptive card message.
|
|
3014
|
+
*
|
|
3015
|
+
* @param card - the adaptive card raw JSON.
|
|
3016
|
+
* @param onError - an optional error handler that can catch exceptions during adaptive card sending.
|
|
3017
|
+
* If not defined, error will be handled by `BotAdapter.onTurnError`.
|
|
3018
|
+
* @returns the response of sending adaptive card message.
|
|
3019
|
+
*/
|
|
3020
|
+
sendAdaptiveCard(card, onError) {
|
|
3021
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3022
|
+
const response = {};
|
|
3023
|
+
yield this.adapter.continueConversation(this.conversationReference, (context) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3024
|
+
try {
|
|
3025
|
+
const res = yield context.sendActivity({
|
|
2514
3026
|
attachments: [botbuilder.CardFactory.adaptiveCard(card)],
|
|
2515
3027
|
});
|
|
2516
|
-
|
|
3028
|
+
response.id = res === null || res === void 0 ? void 0 : res.id;
|
|
3029
|
+
}
|
|
3030
|
+
catch (error) {
|
|
3031
|
+
if (onError) {
|
|
3032
|
+
yield onError(context, error);
|
|
3033
|
+
}
|
|
3034
|
+
else {
|
|
3035
|
+
throw error;
|
|
3036
|
+
}
|
|
3037
|
+
}
|
|
3038
|
+
}));
|
|
3039
|
+
return response;
|
|
3040
|
+
});
|
|
3041
|
+
}
|
|
3042
|
+
/**
|
|
3043
|
+
* Get channels from this bot installation.
|
|
3044
|
+
*
|
|
3045
|
+
* @returns an array of channels if bot is installed into a team, otherwise returns an empty array.
|
|
3046
|
+
*/
|
|
3047
|
+
channels() {
|
|
3048
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3049
|
+
const channels = [];
|
|
3050
|
+
if (this.type !== exports.NotificationTargetType.Channel) {
|
|
3051
|
+
return channels;
|
|
3052
|
+
}
|
|
3053
|
+
let teamsChannels = [];
|
|
3054
|
+
yield this.adapter.continueConversation(this.conversationReference, (context) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3055
|
+
const teamId = getTeamsBotInstallationId(context);
|
|
3056
|
+
if (teamId !== undefined) {
|
|
3057
|
+
teamsChannels = yield botbuilder.TeamsInfo.getTeamChannels(context, teamId);
|
|
3058
|
+
}
|
|
2517
3059
|
}));
|
|
3060
|
+
for (const channel of teamsChannels) {
|
|
3061
|
+
channels.push(new Channel(this, channel));
|
|
3062
|
+
}
|
|
3063
|
+
return channels;
|
|
3064
|
+
});
|
|
3065
|
+
}
|
|
3066
|
+
/**
|
|
3067
|
+
* Get members from this bot installation.
|
|
3068
|
+
*
|
|
3069
|
+
* @returns an array of members from where the bot is installed.
|
|
3070
|
+
*/
|
|
3071
|
+
members() {
|
|
3072
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3073
|
+
const members = [];
|
|
3074
|
+
yield this.adapter.continueConversation(this.conversationReference, (context) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3075
|
+
let continuationToken;
|
|
3076
|
+
do {
|
|
3077
|
+
const pagedMembers = yield botbuilder.TeamsInfo.getPagedMembers(context, undefined, continuationToken);
|
|
3078
|
+
continuationToken = pagedMembers.continuationToken;
|
|
3079
|
+
for (const member of pagedMembers.members) {
|
|
3080
|
+
members.push(new Member(this, member));
|
|
3081
|
+
}
|
|
3082
|
+
} while (continuationToken !== undefined);
|
|
3083
|
+
}));
|
|
3084
|
+
return members;
|
|
3085
|
+
});
|
|
3086
|
+
}
|
|
3087
|
+
/**
|
|
3088
|
+
* Get team details from this bot installation
|
|
3089
|
+
*
|
|
3090
|
+
* @returns the team details if bot is installed into a team, otherwise returns undefined.
|
|
3091
|
+
*/
|
|
3092
|
+
getTeamDetails() {
|
|
3093
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3094
|
+
if (this.type !== exports.NotificationTargetType.Channel) {
|
|
3095
|
+
return undefined;
|
|
3096
|
+
}
|
|
3097
|
+
let teamDetails;
|
|
3098
|
+
yield this.adapter.continueConversation(this.conversationReference, (context) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3099
|
+
const teamId = getTeamsBotInstallationId(context);
|
|
3100
|
+
if (teamId !== undefined) {
|
|
3101
|
+
teamDetails = yield botbuilder.TeamsInfo.getTeamDetails(context, teamId);
|
|
3102
|
+
}
|
|
3103
|
+
}));
|
|
3104
|
+
return teamDetails;
|
|
3105
|
+
});
|
|
3106
|
+
}
|
|
3107
|
+
}
|
|
3108
|
+
/**
|
|
3109
|
+
* Provide utilities to send notification to varies targets (e.g., member, group, channel).
|
|
3110
|
+
*/
|
|
3111
|
+
class NotificationBot {
|
|
3112
|
+
/**
|
|
3113
|
+
* constructor of the notification bot.
|
|
3114
|
+
*
|
|
3115
|
+
* @remarks
|
|
3116
|
+
* To ensure accuracy, it's recommended to initialize before handling any message.
|
|
3117
|
+
*
|
|
3118
|
+
* @param adapter - the bound `BotFrameworkAdapter`
|
|
3119
|
+
* @param options - initialize options
|
|
3120
|
+
*/
|
|
3121
|
+
constructor(adapter, options) {
|
|
3122
|
+
var _a, _b;
|
|
3123
|
+
const storage = (_a = options === null || options === void 0 ? void 0 : options.storage) !== null && _a !== void 0 ? _a : new LocalFileStorage(path__namespace.resolve(process.env.RUNNING_ON_AZURE === "1" ? (_b = process.env.TEMP) !== null && _b !== void 0 ? _b : "./" : "./"));
|
|
3124
|
+
this.conversationReferenceStore = new ConversationReferenceStore(storage);
|
|
3125
|
+
this.adapter = adapter.use(new NotificationMiddleware({
|
|
3126
|
+
conversationReferenceStore: this.conversationReferenceStore,
|
|
3127
|
+
}));
|
|
3128
|
+
}
|
|
3129
|
+
/**
|
|
3130
|
+
* Get all targets where the bot is installed.
|
|
3131
|
+
*
|
|
3132
|
+
* @remarks
|
|
3133
|
+
* The result is retrieving from the persisted storage.
|
|
3134
|
+
*
|
|
3135
|
+
* @returns - an array of {@link TeamsBotInstallation}.
|
|
3136
|
+
*/
|
|
3137
|
+
installations() {
|
|
3138
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3139
|
+
if (this.conversationReferenceStore === undefined || this.adapter === undefined) {
|
|
3140
|
+
throw new Error("NotificationBot has not been initialized.");
|
|
3141
|
+
}
|
|
3142
|
+
const references = yield this.conversationReferenceStore.getAll();
|
|
3143
|
+
const targets = [];
|
|
3144
|
+
for (const reference of references) {
|
|
3145
|
+
// validate connection
|
|
3146
|
+
let valid = true;
|
|
3147
|
+
yield this.adapter.continueConversation(reference, (context) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3148
|
+
try {
|
|
3149
|
+
// try get member to see if the installation is still valid
|
|
3150
|
+
yield botbuilder.TeamsInfo.getPagedMembers(context, 1);
|
|
3151
|
+
}
|
|
3152
|
+
catch (error) {
|
|
3153
|
+
if (error.code === "BotNotInConversationRoster") {
|
|
3154
|
+
valid = false;
|
|
3155
|
+
}
|
|
3156
|
+
}
|
|
3157
|
+
}));
|
|
3158
|
+
if (valid) {
|
|
3159
|
+
targets.push(new TeamsBotInstallation(this.adapter, reference));
|
|
3160
|
+
}
|
|
3161
|
+
else {
|
|
3162
|
+
yield this.conversationReferenceStore.delete(reference);
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
return targets;
|
|
3166
|
+
});
|
|
3167
|
+
}
|
|
3168
|
+
/**
|
|
3169
|
+
* Returns the first {@link Member} where predicate is true, and undefined otherwise.
|
|
3170
|
+
*
|
|
3171
|
+
* @param predicate find calls predicate once for each member of the installation,
|
|
3172
|
+
* until it finds one where predicate returns true. If such a member is found, find
|
|
3173
|
+
* immediately returns that member. Otherwise, find returns undefined.
|
|
3174
|
+
* @param scope the scope to find members from the installations
|
|
3175
|
+
* (personal chat, group chat, Teams channel).
|
|
3176
|
+
* @returns the first {@link Member} where predicate is true, and undefined otherwise.
|
|
3177
|
+
*/
|
|
3178
|
+
findMember(predicate, scope) {
|
|
3179
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3180
|
+
for (const target of yield this.installations()) {
|
|
3181
|
+
if (this.matchSearchScope(target, scope)) {
|
|
3182
|
+
for (const member of yield target.members()) {
|
|
3183
|
+
if (yield predicate(member)) {
|
|
3184
|
+
return member;
|
|
3185
|
+
}
|
|
3186
|
+
}
|
|
3187
|
+
}
|
|
3188
|
+
}
|
|
3189
|
+
return;
|
|
3190
|
+
});
|
|
3191
|
+
}
|
|
3192
|
+
/**
|
|
3193
|
+
* Returns the first {@link Channel} where predicate is true, and undefined otherwise.
|
|
3194
|
+
* (Ensure the bot app is installed into the `General` channel, otherwise undefined will be returned.)
|
|
3195
|
+
*
|
|
3196
|
+
* @param predicate find calls predicate once for each channel of the installation,
|
|
3197
|
+
* until it finds one where predicate returns true. If such a channel is found, find
|
|
3198
|
+
* immediately returns that channel. Otherwise, find returns undefined.
|
|
3199
|
+
* @returns the first {@link Channel} where predicate is true, and undefined otherwise.
|
|
3200
|
+
*/
|
|
3201
|
+
findChannel(predicate) {
|
|
3202
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3203
|
+
for (const target of yield this.installations()) {
|
|
3204
|
+
if (target.type === exports.NotificationTargetType.Channel) {
|
|
3205
|
+
const teamDetails = yield target.getTeamDetails();
|
|
3206
|
+
for (const channel of yield target.channels()) {
|
|
3207
|
+
if (yield predicate(channel, teamDetails)) {
|
|
3208
|
+
return channel;
|
|
3209
|
+
}
|
|
3210
|
+
}
|
|
3211
|
+
}
|
|
3212
|
+
}
|
|
3213
|
+
return;
|
|
2518
3214
|
});
|
|
2519
3215
|
}
|
|
2520
3216
|
/**
|
|
3217
|
+
* Returns all {@link Member} where predicate is true, and empty array otherwise.
|
|
3218
|
+
*
|
|
3219
|
+
* @param predicate find calls predicate for each member of the installation.
|
|
3220
|
+
* @param scope the scope to find members from the installations
|
|
3221
|
+
* (personal chat, group chat, Teams channel).
|
|
3222
|
+
* @returns an array of {@link Member} where predicate is true, and empty array otherwise.
|
|
3223
|
+
*/
|
|
3224
|
+
findAllMembers(predicate, scope) {
|
|
3225
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3226
|
+
const members = [];
|
|
3227
|
+
for (const target of yield this.installations()) {
|
|
3228
|
+
if (this.matchSearchScope(target, scope)) {
|
|
3229
|
+
for (const member of yield target.members()) {
|
|
3230
|
+
if (yield predicate(member)) {
|
|
3231
|
+
members.push(member);
|
|
3232
|
+
}
|
|
3233
|
+
}
|
|
3234
|
+
}
|
|
3235
|
+
}
|
|
3236
|
+
return members;
|
|
3237
|
+
});
|
|
3238
|
+
}
|
|
3239
|
+
/**
|
|
3240
|
+
* Returns all {@link Channel} where predicate is true, and empty array otherwise.
|
|
3241
|
+
* (Ensure the bot app is installed into the `General` channel, otherwise empty array will be returned.)
|
|
3242
|
+
*
|
|
3243
|
+
* @param predicate find calls predicate for each channel of the installation.
|
|
3244
|
+
* @returns an array of {@link Channel} where predicate is true, and empty array otherwise.
|
|
3245
|
+
*/
|
|
3246
|
+
findAllChannels(predicate) {
|
|
3247
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3248
|
+
const channels = [];
|
|
3249
|
+
for (const target of yield this.installations()) {
|
|
3250
|
+
if (target.type === exports.NotificationTargetType.Channel) {
|
|
3251
|
+
const teamDetails = yield target.getTeamDetails();
|
|
3252
|
+
for (const channel of yield target.channels()) {
|
|
3253
|
+
if (yield predicate(channel, teamDetails)) {
|
|
3254
|
+
channels.push(channel);
|
|
3255
|
+
}
|
|
3256
|
+
}
|
|
3257
|
+
}
|
|
3258
|
+
}
|
|
3259
|
+
return channels;
|
|
3260
|
+
});
|
|
3261
|
+
}
|
|
3262
|
+
matchSearchScope(target, scope) {
|
|
3263
|
+
scope = scope !== null && scope !== void 0 ? scope : exports.SearchScope.All;
|
|
3264
|
+
return ((target.type === exports.NotificationTargetType.Channel && (scope & exports.SearchScope.Channel) !== 0) ||
|
|
3265
|
+
(target.type === exports.NotificationTargetType.Group && (scope & exports.SearchScope.Group) !== 0) ||
|
|
3266
|
+
(target.type === exports.NotificationTargetType.Person && (scope & exports.SearchScope.Person) !== 0));
|
|
3267
|
+
}
|
|
3268
|
+
}
|
|
3269
|
+
/**
|
|
3270
|
+
* The search scope when calling {@link NotificationBot.findMember} and {@link NotificationBot.findAllMembers}.
|
|
3271
|
+
* The search scope is a flagged enum and it can be combined with `|`.
|
|
3272
|
+
* For example, to search from personal chat and group chat, use `SearchScope.Person | SearchScope.Group`.
|
|
3273
|
+
*/
|
|
3274
|
+
exports.SearchScope = void 0;
|
|
3275
|
+
(function (SearchScope) {
|
|
3276
|
+
/**
|
|
3277
|
+
* Search members from the installations in personal chat only.
|
|
3278
|
+
*/
|
|
3279
|
+
SearchScope[SearchScope["Person"] = 1] = "Person";
|
|
3280
|
+
/**
|
|
3281
|
+
* Search members from the installations in group chat only.
|
|
3282
|
+
*/
|
|
3283
|
+
SearchScope[SearchScope["Group"] = 2] = "Group";
|
|
3284
|
+
/**
|
|
3285
|
+
* Search members from the installations in Teams channel only.
|
|
3286
|
+
*/
|
|
3287
|
+
SearchScope[SearchScope["Channel"] = 4] = "Channel";
|
|
3288
|
+
/**
|
|
3289
|
+
* Search members from all installations including personal chat, group chat and Teams channel.
|
|
3290
|
+
*/
|
|
3291
|
+
SearchScope[SearchScope["All"] = 7] = "All";
|
|
3292
|
+
})(exports.SearchScope || (exports.SearchScope = {}));
|
|
3293
|
+
|
|
3294
|
+
// Copyright (c) Microsoft Corporation.
|
|
3295
|
+
let DIALOG_NAME = "BotSsoExecutionDialog";
|
|
3296
|
+
let TEAMS_SSO_PROMPT_ID = "TeamsFxSsoPrompt";
|
|
3297
|
+
let COMMAND_ROUTE_DIALOG = "CommandRouteDialog";
|
|
3298
|
+
/**
|
|
3299
|
+
* Sso execution dialog, use to handle sso command
|
|
3300
|
+
*/
|
|
3301
|
+
class BotSsoExecutionDialog extends botbuilderDialogs.ComponentDialog {
|
|
3302
|
+
constructor(dedupStorage, ssoPromptSettings, authConfig, ...args) {
|
|
3303
|
+
var _a;
|
|
3304
|
+
super((_a = (authConfig.getCredential ? args[0] : args[1])) !== null && _a !== void 0 ? _a : DIALOG_NAME);
|
|
3305
|
+
this.dedupStorageKeys = [];
|
|
3306
|
+
// Map to store the commandId and triggerPatterns, key: commandId, value: triggerPatterns
|
|
3307
|
+
this.commandMapping = new Map();
|
|
3308
|
+
const dialogName = authConfig.getCredential ? args[0] : args[1];
|
|
3309
|
+
if (dialogName) {
|
|
3310
|
+
DIALOG_NAME = dialogName;
|
|
3311
|
+
TEAMS_SSO_PROMPT_ID = dialogName + TEAMS_SSO_PROMPT_ID;
|
|
3312
|
+
COMMAND_ROUTE_DIALOG = dialogName + COMMAND_ROUTE_DIALOG;
|
|
3313
|
+
}
|
|
3314
|
+
let ssoDialog;
|
|
3315
|
+
if (authConfig.getCredential) {
|
|
3316
|
+
ssoDialog = new TeamsBotSsoPrompt(authConfig, TEAMS_SSO_PROMPT_ID, ssoPromptSettings);
|
|
3317
|
+
}
|
|
3318
|
+
else {
|
|
3319
|
+
ssoDialog = new TeamsBotSsoPrompt(authConfig, args[0], TEAMS_SSO_PROMPT_ID, ssoPromptSettings);
|
|
3320
|
+
}
|
|
3321
|
+
this.addDialog(ssoDialog);
|
|
3322
|
+
this.initialDialogId = COMMAND_ROUTE_DIALOG;
|
|
3323
|
+
this.dedupStorage = dedupStorage;
|
|
3324
|
+
this.dedupStorageKeys = [];
|
|
3325
|
+
const commandRouteDialog = new botbuilderDialogs.WaterfallDialog(COMMAND_ROUTE_DIALOG, [
|
|
3326
|
+
this.commandRouteStep.bind(this),
|
|
3327
|
+
]);
|
|
3328
|
+
this.addDialog(commandRouteDialog);
|
|
3329
|
+
}
|
|
3330
|
+
/**
|
|
3331
|
+
* Add TeamsFxBotSsoCommandHandler instance
|
|
3332
|
+
* @param handler {@link BotSsoExecutionDialogHandler} callback function
|
|
3333
|
+
* @param triggerPatterns The trigger pattern
|
|
3334
|
+
*/
|
|
3335
|
+
addCommand(handler, triggerPatterns) {
|
|
3336
|
+
const commandId = this.getCommandHash(triggerPatterns);
|
|
3337
|
+
const dialog = new botbuilderDialogs.WaterfallDialog(commandId, [
|
|
3338
|
+
this.ssoStep.bind(this),
|
|
3339
|
+
this.dedupStep.bind(this),
|
|
3340
|
+
(stepContext) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3341
|
+
const tokenResponse = stepContext.result.tokenResponse;
|
|
3342
|
+
const context = stepContext.context;
|
|
3343
|
+
const message = stepContext.result.message;
|
|
3344
|
+
try {
|
|
3345
|
+
if (tokenResponse) {
|
|
3346
|
+
yield handler(context, tokenResponse, message);
|
|
3347
|
+
}
|
|
3348
|
+
else {
|
|
3349
|
+
throw new Error(ErrorMessage.FailedToRetrieveSsoToken);
|
|
3350
|
+
}
|
|
3351
|
+
return yield stepContext.endDialog();
|
|
3352
|
+
}
|
|
3353
|
+
catch (error) {
|
|
3354
|
+
const errorMsg = formatString(ErrorMessage.FailedToProcessSsoHandler, error.message);
|
|
3355
|
+
internalLogger.error(errorMsg);
|
|
3356
|
+
return yield stepContext.endDialog(new ErrorWithCode(errorMsg, exports.ErrorCode.FailedToProcessSsoHandler));
|
|
3357
|
+
}
|
|
3358
|
+
}),
|
|
3359
|
+
]);
|
|
3360
|
+
this.commandMapping.set(commandId, triggerPatterns);
|
|
3361
|
+
this.addDialog(dialog);
|
|
3362
|
+
}
|
|
3363
|
+
getCommandHash(patterns) {
|
|
3364
|
+
const expressions = Array.isArray(patterns) ? patterns : [patterns];
|
|
3365
|
+
const patternStr = expressions.join();
|
|
3366
|
+
const patternStrWithoutSpecialChar = patternStr.replace(/[^a-zA-Z0-9]/g, "");
|
|
3367
|
+
const hash = crypto.createHash("sha256").update(patternStr).digest("hex").toLowerCase();
|
|
3368
|
+
return patternStrWithoutSpecialChar + hash;
|
|
3369
|
+
}
|
|
3370
|
+
/**
|
|
3371
|
+
* The run method handles the incoming activity (in the form of a DialogContext) and passes it through the dialog system.
|
|
3372
|
+
*
|
|
3373
|
+
* @param context The context object for the current turn.
|
|
3374
|
+
* @param accessor The instance of StatePropertyAccessor for dialog system.
|
|
3375
|
+
*/
|
|
3376
|
+
run(context, accessor) {
|
|
3377
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3378
|
+
const dialogSet = new botbuilderDialogs.DialogSet(accessor);
|
|
3379
|
+
dialogSet.add(this);
|
|
3380
|
+
const dialogContext = yield dialogSet.createContext(context);
|
|
3381
|
+
this.ensureMsTeamsChannel(dialogContext);
|
|
3382
|
+
const results = yield dialogContext.continueDialog();
|
|
3383
|
+
if (results && results.status === botbuilderDialogs.DialogTurnStatus.empty) {
|
|
3384
|
+
yield dialogContext.beginDialog(this.id);
|
|
3385
|
+
}
|
|
3386
|
+
else if (results &&
|
|
3387
|
+
results.status === botbuilderDialogs.DialogTurnStatus.complete &&
|
|
3388
|
+
results.result instanceof Error) {
|
|
3389
|
+
throw results.result;
|
|
3390
|
+
}
|
|
3391
|
+
});
|
|
3392
|
+
}
|
|
3393
|
+
getActivityText(activity) {
|
|
3394
|
+
let text = activity.text;
|
|
3395
|
+
const removedMentionText = botbuilder.TurnContext.removeRecipientMention(activity);
|
|
3396
|
+
if (removedMentionText) {
|
|
3397
|
+
text = removedMentionText
|
|
3398
|
+
.toLowerCase()
|
|
3399
|
+
.replace(/\n|\r\n/g, "")
|
|
3400
|
+
.trim();
|
|
3401
|
+
}
|
|
3402
|
+
return text;
|
|
3403
|
+
}
|
|
3404
|
+
commandRouteStep(stepContext) {
|
|
3405
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3406
|
+
const turnContext = stepContext.context;
|
|
3407
|
+
const text = this.getActivityText(turnContext.activity);
|
|
3408
|
+
const commandId = this.getMatchesCommandId(text);
|
|
3409
|
+
if (commandId) {
|
|
3410
|
+
return yield stepContext.beginDialog(commandId);
|
|
3411
|
+
}
|
|
3412
|
+
const errorMsg = formatString(ErrorMessage.CannotFindCommand, turnContext.activity.text);
|
|
3413
|
+
internalLogger.error(errorMsg);
|
|
3414
|
+
throw new ErrorWithCode(errorMsg, exports.ErrorCode.CannotFindCommand);
|
|
3415
|
+
});
|
|
3416
|
+
}
|
|
3417
|
+
ssoStep(stepContext) {
|
|
3418
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3419
|
+
try {
|
|
3420
|
+
const turnContext = stepContext.context;
|
|
3421
|
+
const text = this.getActivityText(turnContext.activity);
|
|
3422
|
+
const message = {
|
|
3423
|
+
text,
|
|
3424
|
+
};
|
|
3425
|
+
stepContext.options.commandMessage = message;
|
|
3426
|
+
return yield stepContext.beginDialog(TEAMS_SSO_PROMPT_ID);
|
|
3427
|
+
}
|
|
3428
|
+
catch (error) {
|
|
3429
|
+
const errorMsg = formatString(ErrorMessage.FailedToRunSsoStep, error.message);
|
|
3430
|
+
internalLogger.error(errorMsg);
|
|
3431
|
+
return yield stepContext.endDialog(new ErrorWithCode(errorMsg, exports.ErrorCode.FailedToRunSsoStep));
|
|
3432
|
+
}
|
|
3433
|
+
});
|
|
3434
|
+
}
|
|
3435
|
+
dedupStep(stepContext) {
|
|
3436
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3437
|
+
const tokenResponse = stepContext.result;
|
|
3438
|
+
if (!tokenResponse) {
|
|
3439
|
+
internalLogger.error(ErrorMessage.FailedToRetrieveSsoToken);
|
|
3440
|
+
return yield stepContext.endDialog(new ErrorWithCode(ErrorMessage.FailedToRetrieveSsoToken, exports.ErrorCode.FailedToRunSsoStep));
|
|
3441
|
+
}
|
|
3442
|
+
try {
|
|
3443
|
+
// Only dedup after ssoStep to make sure that all Teams client would receive the login request
|
|
3444
|
+
if (tokenResponse && (yield this.shouldDedup(stepContext.context))) {
|
|
3445
|
+
return botbuilderDialogs.Dialog.EndOfTurn;
|
|
3446
|
+
}
|
|
3447
|
+
return yield stepContext.next({
|
|
3448
|
+
tokenResponse,
|
|
3449
|
+
message: stepContext.options.commandMessage,
|
|
3450
|
+
});
|
|
3451
|
+
}
|
|
3452
|
+
catch (error) {
|
|
3453
|
+
const errorMsg = formatString(ErrorMessage.FailedToRunDedupStep, error.message);
|
|
3454
|
+
internalLogger.error(errorMsg);
|
|
3455
|
+
return yield stepContext.endDialog(new ErrorWithCode(errorMsg, exports.ErrorCode.FailedToRunDedupStep));
|
|
3456
|
+
}
|
|
3457
|
+
});
|
|
3458
|
+
}
|
|
3459
|
+
/**
|
|
3460
|
+
* Called when the component is ending.
|
|
3461
|
+
*
|
|
3462
|
+
* @param context Context for the current turn of conversation.
|
|
3463
|
+
*/
|
|
3464
|
+
onEndDialog(context) {
|
|
3465
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3466
|
+
const conversationId = context.activity.conversation.id;
|
|
3467
|
+
const currentDedupKeys = this.dedupStorageKeys.filter((key) => key.indexOf(conversationId) > 0);
|
|
3468
|
+
yield this.dedupStorage.delete(currentDedupKeys);
|
|
3469
|
+
this.dedupStorageKeys = this.dedupStorageKeys.filter((key) => key.indexOf(conversationId) < 0);
|
|
3470
|
+
});
|
|
3471
|
+
}
|
|
3472
|
+
/**
|
|
3473
|
+
* If a user is signed into multiple Teams clients, the Bot might receive a "signin/tokenExchange" from each client.
|
|
3474
|
+
* Each token exchange request for a specific user login will have an identical activity.value.Id.
|
|
3475
|
+
* Only one of these token exchange requests should be processed by the bot. For a distributed bot in production,
|
|
3476
|
+
* this requires a distributed storage to ensure only one token exchange is processed.
|
|
3477
|
+
* @param context Context for the current turn of conversation.
|
|
3478
|
+
* @returns boolean value indicate whether the message should be removed
|
|
3479
|
+
*/
|
|
3480
|
+
shouldDedup(context) {
|
|
3481
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3482
|
+
const storeItem = {
|
|
3483
|
+
eTag: context.activity.value.id,
|
|
3484
|
+
};
|
|
3485
|
+
const key = this.getStorageKey(context);
|
|
3486
|
+
const storeItems = { [key]: storeItem };
|
|
3487
|
+
try {
|
|
3488
|
+
yield this.dedupStorage.write(storeItems);
|
|
3489
|
+
this.dedupStorageKeys.push(key);
|
|
3490
|
+
}
|
|
3491
|
+
catch (err) {
|
|
3492
|
+
if (err instanceof Error && err.message.indexOf("eTag conflict")) {
|
|
3493
|
+
return true;
|
|
3494
|
+
}
|
|
3495
|
+
throw err;
|
|
3496
|
+
}
|
|
3497
|
+
return false;
|
|
3498
|
+
});
|
|
3499
|
+
}
|
|
3500
|
+
getStorageKey(context) {
|
|
3501
|
+
if (!context || !context.activity || !context.activity.conversation) {
|
|
3502
|
+
throw new Error("Invalid context, can not get storage key!");
|
|
3503
|
+
}
|
|
3504
|
+
const activity = context.activity;
|
|
3505
|
+
const channelId = activity.channelId;
|
|
3506
|
+
const conversationId = activity.conversation.id;
|
|
3507
|
+
if (activity.type !== botbuilder.ActivityTypes.Invoke || activity.name !== botbuilder.tokenExchangeOperationName) {
|
|
3508
|
+
throw new Error("TokenExchangeState can only be used with Invokes of signin/tokenExchange.");
|
|
3509
|
+
}
|
|
3510
|
+
const value = activity.value;
|
|
3511
|
+
if (!value || !value.id) {
|
|
3512
|
+
throw new Error("Invalid signin/tokenExchange. Missing activity.value.id.");
|
|
3513
|
+
}
|
|
3514
|
+
return `${channelId}/${conversationId}/${value.id}`;
|
|
3515
|
+
}
|
|
3516
|
+
matchPattern(pattern, text) {
|
|
3517
|
+
if (text) {
|
|
3518
|
+
if (typeof pattern === "string") {
|
|
3519
|
+
const regExp = new RegExp(pattern, "i");
|
|
3520
|
+
return regExp.test(text);
|
|
3521
|
+
}
|
|
3522
|
+
if (pattern instanceof RegExp) {
|
|
3523
|
+
const matches = text.match(pattern);
|
|
3524
|
+
return matches !== null && matches !== void 0 ? matches : false;
|
|
3525
|
+
}
|
|
3526
|
+
}
|
|
3527
|
+
return false;
|
|
3528
|
+
}
|
|
3529
|
+
isPatternMatched(patterns, text) {
|
|
3530
|
+
const expressions = Array.isArray(patterns) ? patterns : [patterns];
|
|
3531
|
+
for (const ex of expressions) {
|
|
3532
|
+
const matches = this.matchPattern(ex, text);
|
|
3533
|
+
return !!matches;
|
|
3534
|
+
}
|
|
3535
|
+
return false;
|
|
3536
|
+
}
|
|
3537
|
+
getMatchesCommandId(text) {
|
|
3538
|
+
for (const command of this.commandMapping) {
|
|
3539
|
+
const pattern = command[1];
|
|
3540
|
+
if (this.isPatternMatched(pattern, text)) {
|
|
3541
|
+
return command[0];
|
|
3542
|
+
}
|
|
3543
|
+
}
|
|
3544
|
+
return undefined;
|
|
3545
|
+
}
|
|
3546
|
+
/**
|
|
3547
|
+
* Ensure bot is running in MS Teams since TeamsBotSsoPrompt is only supported in MS Teams channel.
|
|
3548
|
+
* @param dc dialog context
|
|
3549
|
+
* @throws {@link ErrorCode|ChannelNotSupported} if bot channel is not MS Teams
|
|
2521
3550
|
* @internal
|
|
2522
3551
|
*/
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
const
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
isGroup: false,
|
|
2530
|
-
tenantId: context.activity.conversation.tenantId,
|
|
2531
|
-
bot: context.activity.recipient,
|
|
2532
|
-
members: [this.account],
|
|
2533
|
-
channelData: {},
|
|
2534
|
-
});
|
|
2535
|
-
personalConversation.conversation.id = conversation.id;
|
|
2536
|
-
return personalConversation;
|
|
2537
|
-
});
|
|
3552
|
+
ensureMsTeamsChannel(dc) {
|
|
3553
|
+
if (dc.context.activity.channelId != botbuilder.Channels.Msteams) {
|
|
3554
|
+
const errorMsg = formatString(ErrorMessage.OnlyMSTeamsChannelSupported, "SSO execution dialog");
|
|
3555
|
+
internalLogger.error(errorMsg);
|
|
3556
|
+
throw new ErrorWithCode(errorMsg, exports.ErrorCode.ChannelNotSupported);
|
|
3557
|
+
}
|
|
2538
3558
|
}
|
|
2539
|
-
}
|
|
3559
|
+
}
|
|
3560
|
+
|
|
3561
|
+
// Copyright (c) Microsoft Corporation.
|
|
2540
3562
|
/**
|
|
2541
|
-
*
|
|
2542
|
-
* - Personal chat
|
|
2543
|
-
* - Group chat
|
|
2544
|
-
* - Team (by default the `General` channel)
|
|
2545
|
-
*
|
|
2546
|
-
* @remarks
|
|
2547
|
-
* It's recommended to get bot installations from {@link ConversationBot.installations()}.
|
|
2548
|
-
*
|
|
2549
|
-
* @beta
|
|
3563
|
+
* Default SSO execution activity handler
|
|
2550
3564
|
*/
|
|
2551
|
-
class
|
|
3565
|
+
class DefaultBotSsoExecutionActivityHandler extends botbuilder.TeamsActivityHandler {
|
|
2552
3566
|
/**
|
|
2553
|
-
*
|
|
3567
|
+
* Creates a new instance of the DefaultBotSsoExecutionActivityHandler.
|
|
3568
|
+
* @param ssoConfig configuration for SSO command bot
|
|
2554
3569
|
*
|
|
2555
3570
|
* @remarks
|
|
2556
|
-
*
|
|
2557
|
-
*
|
|
2558
|
-
* @param adapter - the bound `BotFrameworkAdapter`.
|
|
2559
|
-
* @param conversationReference - the bound `ConversationReference`.
|
|
2560
|
-
*
|
|
2561
|
-
* @beta
|
|
2562
|
-
*/
|
|
2563
|
-
constructor(adapter, conversationReference) {
|
|
2564
|
-
this.adapter = adapter;
|
|
2565
|
-
this.conversationReference = conversationReference;
|
|
2566
|
-
this.type = getTargetType(conversationReference);
|
|
2567
|
-
}
|
|
2568
|
-
/**
|
|
2569
|
-
* Send a plain text message.
|
|
2570
|
-
*
|
|
2571
|
-
* @param text - the plain text message.
|
|
2572
|
-
* @returns A `Promise` representing the asynchronous operation.
|
|
2573
|
-
*
|
|
2574
|
-
* @beta
|
|
3571
|
+
* In the constructor, it uses BotSsoConfig parameter which from {@link ConversationBot} options to initialize {@link BotSsoExecutionDialog}.
|
|
3572
|
+
* It also need to register an event handler for the message event which trigger {@link BotSsoExecutionDialog} instance.
|
|
2575
3573
|
*/
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
3574
|
+
constructor(ssoConfig) {
|
|
3575
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
3576
|
+
super();
|
|
3577
|
+
const memoryStorage = new botbuilder.MemoryStorage();
|
|
3578
|
+
const userState = (_b = (_a = ssoConfig.dialog) === null || _a === void 0 ? void 0 : _a.userState) !== null && _b !== void 0 ? _b : new botbuilder.UserState(memoryStorage);
|
|
3579
|
+
const conversationState = (_d = (_c = ssoConfig.dialog) === null || _c === void 0 ? void 0 : _c.conversationState) !== null && _d !== void 0 ? _d : new botbuilder.ConversationState(memoryStorage);
|
|
3580
|
+
const dedupStorage = (_f = (_e = ssoConfig.dialog) === null || _e === void 0 ? void 0 : _e.dedupStorage) !== null && _f !== void 0 ? _f : memoryStorage;
|
|
3581
|
+
const _l = ssoConfig.aad, { scopes } = _l, customConfig = tslib.__rest(_l, ["scopes"]);
|
|
3582
|
+
const settings = {
|
|
3583
|
+
scopes: scopes,
|
|
3584
|
+
timeout: (_h = (_g = ssoConfig.dialog) === null || _g === void 0 ? void 0 : _g.ssoPromptConfig) === null || _h === void 0 ? void 0 : _h.timeout,
|
|
3585
|
+
endOnInvalidMessage: (_k = (_j = ssoConfig.dialog) === null || _j === void 0 ? void 0 : _j.ssoPromptConfig) === null || _k === void 0 ? void 0 : _k.endOnInvalidMessage,
|
|
3586
|
+
};
|
|
3587
|
+
const teamsfx = new TeamsFx(exports.IdentityType.User, Object.assign({}, customConfig));
|
|
3588
|
+
this.ssoExecutionDialog = new BotSsoExecutionDialog(dedupStorage, settings, teamsfx);
|
|
3589
|
+
this.conversationState = conversationState;
|
|
3590
|
+
this.dialogState = conversationState.createProperty("DialogState");
|
|
3591
|
+
this.userState = userState;
|
|
3592
|
+
this.onMessage((context, next) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3593
|
+
yield this.ssoExecutionDialog.run(context, this.dialogState);
|
|
3594
|
+
yield next();
|
|
2579
3595
|
}));
|
|
2580
3596
|
}
|
|
2581
3597
|
/**
|
|
2582
|
-
*
|
|
2583
|
-
*
|
|
2584
|
-
* @param
|
|
2585
|
-
* @returns A `Promise` representing the asynchronous operation.
|
|
3598
|
+
* Add TeamsFxBotSsoCommandHandler instance to SSO execution dialog
|
|
3599
|
+
* @param handler {@link BotSsoExecutionDialogHandler} callback function
|
|
3600
|
+
* @param triggerPatterns The trigger pattern
|
|
2586
3601
|
*
|
|
2587
|
-
* @
|
|
3602
|
+
* @remarks
|
|
3603
|
+
* This function is used to add SSO command to {@link BotSsoExecutionDialog} instance.
|
|
2588
3604
|
*/
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
yield context.sendActivity({
|
|
2592
|
-
attachments: [botbuilder.CardFactory.adaptiveCard(card)],
|
|
2593
|
-
});
|
|
2594
|
-
}));
|
|
3605
|
+
addCommand(handler, triggerPatterns) {
|
|
3606
|
+
this.ssoExecutionDialog.addCommand(handler, triggerPatterns);
|
|
2595
3607
|
}
|
|
2596
3608
|
/**
|
|
2597
|
-
*
|
|
2598
|
-
*
|
|
2599
|
-
* @returns an array of channels if bot is installed into a team, otherwise returns an empty array.
|
|
2600
|
-
*
|
|
2601
|
-
* @beta
|
|
3609
|
+
* Called to initiate the event emission process.
|
|
3610
|
+
* @param context The context object for the current turn.
|
|
2602
3611
|
*/
|
|
2603
|
-
|
|
3612
|
+
run(context) {
|
|
3613
|
+
const _super = Object.create(null, {
|
|
3614
|
+
run: { get: () => super.run }
|
|
3615
|
+
});
|
|
2604
3616
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
}));
|
|
2612
|
-
const channels = [];
|
|
2613
|
-
for (const channel of teamsChannels) {
|
|
2614
|
-
channels.push(new Channel(this, channel));
|
|
3617
|
+
try {
|
|
3618
|
+
yield _super.run.call(this, context);
|
|
3619
|
+
}
|
|
3620
|
+
finally {
|
|
3621
|
+
yield this.conversationState.saveChanges(context, false);
|
|
3622
|
+
yield this.userState.saveChanges(context, false);
|
|
2615
3623
|
}
|
|
2616
|
-
return channels;
|
|
2617
3624
|
});
|
|
2618
3625
|
}
|
|
2619
3626
|
/**
|
|
2620
|
-
*
|
|
2621
|
-
*
|
|
2622
|
-
* @
|
|
3627
|
+
* Receives invoke activities with Activity name of 'signin/verifyState'.
|
|
3628
|
+
* @param context A context object for this turn.
|
|
3629
|
+
* @param query Signin state (part of signin action auth flow) verification invoke query.
|
|
3630
|
+
* @returns A promise that represents the work queued.
|
|
2623
3631
|
*
|
|
2624
|
-
* @
|
|
3632
|
+
* @remarks
|
|
3633
|
+
* It should trigger {@link BotSsoExecutionDialog} instance to handle signin process
|
|
2625
3634
|
*/
|
|
2626
|
-
|
|
3635
|
+
handleTeamsSigninVerifyState(context, query) {
|
|
2627
3636
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2628
|
-
|
|
2629
|
-
yield this.adapter.continueConversation(this.conversationReference, (context) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2630
|
-
let continuationToken;
|
|
2631
|
-
do {
|
|
2632
|
-
const pagedMembers = yield botbuilder.TeamsInfo.getPagedMembers(context, undefined, continuationToken);
|
|
2633
|
-
continuationToken = pagedMembers.continuationToken;
|
|
2634
|
-
for (const member of pagedMembers.members) {
|
|
2635
|
-
members.push(new Member(this, member));
|
|
2636
|
-
}
|
|
2637
|
-
} while (continuationToken !== undefined);
|
|
2638
|
-
}));
|
|
2639
|
-
return members;
|
|
3637
|
+
yield this.ssoExecutionDialog.run(context, this.dialogState);
|
|
2640
3638
|
});
|
|
2641
3639
|
}
|
|
2642
|
-
}
|
|
2643
|
-
/**
|
|
2644
|
-
* Provide utilities to send notification to varies targets (e.g., member, group, channel).
|
|
2645
|
-
*
|
|
2646
|
-
* @beta
|
|
2647
|
-
*/
|
|
2648
|
-
class NotificationBot {
|
|
2649
|
-
/**
|
|
2650
|
-
* constructor of the notification bot.
|
|
2651
|
-
*
|
|
2652
|
-
* @remarks
|
|
2653
|
-
* To ensure accuracy, it's recommended to initialize before handling any message.
|
|
2654
|
-
*
|
|
2655
|
-
* @param adapter - the bound `BotFrameworkAdapter`
|
|
2656
|
-
* @param options - initialize options
|
|
2657
|
-
*
|
|
2658
|
-
* @beta
|
|
2659
|
-
*/
|
|
2660
|
-
constructor(adapter, options) {
|
|
2661
|
-
var _a, _b;
|
|
2662
|
-
const storage = (_a = options === null || options === void 0 ? void 0 : options.storage) !== null && _a !== void 0 ? _a : new LocalFileStorage(path__namespace.resolve(process.env.RUNNING_ON_AZURE === "1" ? (_b = process.env.TEMP) !== null && _b !== void 0 ? _b : "./" : "./"));
|
|
2663
|
-
this.conversationReferenceStore = new ConversationReferenceStore(storage);
|
|
2664
|
-
this.adapter = adapter.use(new NotificationMiddleware({
|
|
2665
|
-
conversationReferenceStore: this.conversationReferenceStore,
|
|
2666
|
-
}));
|
|
2667
|
-
}
|
|
2668
3640
|
/**
|
|
2669
|
-
*
|
|
2670
|
-
*
|
|
2671
|
-
* @
|
|
2672
|
-
*
|
|
2673
|
-
*
|
|
2674
|
-
* @returns - an array of {@link TeamsBotInstallation}.
|
|
3641
|
+
* Receives invoke activities with Activity name of 'signin/tokenExchange'
|
|
3642
|
+
* @param context A context object for this turn.
|
|
3643
|
+
* @param query Signin state (part of signin action auth flow) verification invoke query
|
|
3644
|
+
* @returns A promise that represents the work queued.
|
|
2675
3645
|
*
|
|
2676
|
-
* @
|
|
3646
|
+
* @remark
|
|
3647
|
+
* It should trigger {@link BotSsoExecutionDialog} instance to handle signin process
|
|
2677
3648
|
*/
|
|
2678
|
-
|
|
3649
|
+
handleTeamsSigninTokenExchange(context, query) {
|
|
2679
3650
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2680
|
-
|
|
2681
|
-
throw new Error("NotificationBot has not been initialized.");
|
|
2682
|
-
}
|
|
2683
|
-
const references = yield this.conversationReferenceStore.getAll();
|
|
2684
|
-
const targets = [];
|
|
2685
|
-
for (const reference of references) {
|
|
2686
|
-
// validate connection
|
|
2687
|
-
let valid = true;
|
|
2688
|
-
yield this.adapter.continueConversation(reference, (context) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2689
|
-
try {
|
|
2690
|
-
// try get member to see if the installation is still valid
|
|
2691
|
-
yield botbuilder.TeamsInfo.getPagedMembers(context, 1);
|
|
2692
|
-
}
|
|
2693
|
-
catch (error) {
|
|
2694
|
-
if (error.code === "BotNotInConversationRoster") {
|
|
2695
|
-
valid = false;
|
|
2696
|
-
}
|
|
2697
|
-
}
|
|
2698
|
-
}));
|
|
2699
|
-
if (valid) {
|
|
2700
|
-
targets.push(new TeamsBotInstallation(this.adapter, reference));
|
|
2701
|
-
}
|
|
2702
|
-
else {
|
|
2703
|
-
yield this.conversationReferenceStore.delete(reference);
|
|
2704
|
-
}
|
|
2705
|
-
}
|
|
2706
|
-
return targets;
|
|
3651
|
+
yield this.ssoExecutionDialog.run(context, this.dialogState);
|
|
2707
3652
|
});
|
|
2708
3653
|
}
|
|
2709
3654
|
}
|
|
@@ -2759,8 +3704,6 @@ class NotificationBot {
|
|
|
2759
3704
|
* For command and response, ensure each command should ONLY be registered with the command once, otherwise it'll cause unexpected behavior if you register the same command more than once.
|
|
2760
3705
|
*
|
|
2761
3706
|
* For notification, set `notification.storage` in {@link ConversationOptions} to use your own storage implementation.
|
|
2762
|
-
*
|
|
2763
|
-
* @beta
|
|
2764
3707
|
*/
|
|
2765
3708
|
class ConversationBot {
|
|
2766
3709
|
/**
|
|
@@ -2770,23 +3713,34 @@ class ConversationBot {
|
|
|
2770
3713
|
* It's recommended to create your own adapter and storage for production environment instead of the default one.
|
|
2771
3714
|
*
|
|
2772
3715
|
* @param options - initialize options
|
|
2773
|
-
*
|
|
2774
|
-
* @beta
|
|
2775
3716
|
*/
|
|
2776
3717
|
constructor(options) {
|
|
2777
|
-
var _a, _b;
|
|
3718
|
+
var _a, _b, _c, _d;
|
|
2778
3719
|
if (options.adapter) {
|
|
2779
3720
|
this.adapter = options.adapter;
|
|
2780
3721
|
}
|
|
2781
3722
|
else {
|
|
2782
3723
|
this.adapter = this.createDefaultAdapter(options.adapterConfig);
|
|
2783
3724
|
}
|
|
2784
|
-
|
|
2785
|
-
|
|
3725
|
+
let ssoCommandActivityHandler;
|
|
3726
|
+
if (options === null || options === void 0 ? void 0 : options.ssoConfig) {
|
|
3727
|
+
if ((_a = options.ssoConfig.dialog) === null || _a === void 0 ? void 0 : _a.CustomBotSsoExecutionActivityHandler) {
|
|
3728
|
+
ssoCommandActivityHandler =
|
|
3729
|
+
new options.ssoConfig.dialog.CustomBotSsoExecutionActivityHandler(options.ssoConfig);
|
|
3730
|
+
}
|
|
3731
|
+
else {
|
|
3732
|
+
ssoCommandActivityHandler = new DefaultBotSsoExecutionActivityHandler(options.ssoConfig);
|
|
3733
|
+
}
|
|
3734
|
+
}
|
|
3735
|
+
if ((_b = options.command) === null || _b === void 0 ? void 0 : _b.enabled) {
|
|
3736
|
+
this.command = new CommandBot(this.adapter, options.command, ssoCommandActivityHandler, options.ssoConfig);
|
|
2786
3737
|
}
|
|
2787
|
-
if ((
|
|
3738
|
+
if ((_c = options.notification) === null || _c === void 0 ? void 0 : _c.enabled) {
|
|
2788
3739
|
this.notification = new NotificationBot(this.adapter, options.notification);
|
|
2789
3740
|
}
|
|
3741
|
+
if ((_d = options.cardAction) === null || _d === void 0 ? void 0 : _d.enabled) {
|
|
3742
|
+
this.cardAction = new CardActionBot(this.adapter, options.cardAction);
|
|
3743
|
+
}
|
|
2790
3744
|
}
|
|
2791
3745
|
createDefaultAdapter(adapterConfig) {
|
|
2792
3746
|
const adapter = adapterConfig === undefined
|
|
@@ -2827,8 +3781,6 @@ class ConversationBot {
|
|
|
2827
3781
|
* });
|
|
2828
3782
|
* });
|
|
2829
3783
|
* ```
|
|
2830
|
-
*
|
|
2831
|
-
* @beta
|
|
2832
3784
|
*/
|
|
2833
3785
|
requestHandler(req, res, logic) {
|
|
2834
3786
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
@@ -2881,8 +3833,6 @@ class MessageBuilder {
|
|
|
2881
3833
|
* description: "sample card description"
|
|
2882
3834
|
* });
|
|
2883
3835
|
* ```
|
|
2884
|
-
*
|
|
2885
|
-
* @beta
|
|
2886
3836
|
*/
|
|
2887
3837
|
static attachAdaptiveCard(cardTemplate, data) {
|
|
2888
3838
|
return {
|
|
@@ -2894,8 +3844,6 @@ class MessageBuilder {
|
|
|
2894
3844
|
*
|
|
2895
3845
|
* @param card The adaptive card content.
|
|
2896
3846
|
* @returns A bot message activity attached with an adaptive card.
|
|
2897
|
-
*
|
|
2898
|
-
* @beta
|
|
2899
3847
|
*/
|
|
2900
3848
|
static attachAdaptiveCardWithoutData(card) {
|
|
2901
3849
|
return {
|
|
@@ -2921,8 +3869,6 @@ class MessageBuilder {
|
|
|
2921
3869
|
* ['action']
|
|
2922
3870
|
* );
|
|
2923
3871
|
* ```
|
|
2924
|
-
*
|
|
2925
|
-
* @beta
|
|
2926
3872
|
*/
|
|
2927
3873
|
static attachHeroCard(title, images, buttons, other) {
|
|
2928
3874
|
return MessageBuilder.attachContent(botbuilder.CardFactory.heroCard(title, images, buttons, other));
|
|
@@ -2938,8 +3884,6 @@ class MessageBuilder {
|
|
|
2938
3884
|
*
|
|
2939
3885
|
* @remarks
|
|
2940
3886
|
* For channels that don't natively support sign-in cards, an alternative message is rendered.
|
|
2941
|
-
*
|
|
2942
|
-
* @beta
|
|
2943
3887
|
*/
|
|
2944
3888
|
static attachSigninCard(title, url, text) {
|
|
2945
3889
|
return MessageBuilder.attachContent(botbuilder.CardFactory.signinCard(title, url, text));
|
|
@@ -2949,8 +3893,6 @@ class MessageBuilder {
|
|
|
2949
3893
|
*
|
|
2950
3894
|
* @param card A description of the Office 365 connector card.
|
|
2951
3895
|
* @returns A bot message activity attached with an Office 365 connector card.
|
|
2952
|
-
*
|
|
2953
|
-
* @beta
|
|
2954
3896
|
*/
|
|
2955
3897
|
static attachO365ConnectorCard(card) {
|
|
2956
3898
|
return MessageBuilder.attachContent(botbuilder.CardFactory.o365ConnectorCard(card));
|
|
@@ -2959,8 +3901,6 @@ class MessageBuilder {
|
|
|
2959
3901
|
* Build a message activity attached with a receipt card.
|
|
2960
3902
|
* @param card A description of the receipt card.
|
|
2961
3903
|
* @returns A message activity attached with a receipt card.
|
|
2962
|
-
*
|
|
2963
|
-
* @beta
|
|
2964
3904
|
*/
|
|
2965
3905
|
static AttachReceiptCard(card) {
|
|
2966
3906
|
return MessageBuilder.attachContent(botbuilder.CardFactory.receiptCard(card));
|
|
@@ -2973,8 +3913,6 @@ class MessageBuilder {
|
|
|
2973
3913
|
* is converted to an `imBack` button with a title and value set to the value of the string.
|
|
2974
3914
|
* @param other Optional. Any additional properties to include on the card.
|
|
2975
3915
|
* @returns A message activity attached with a thumbnail card
|
|
2976
|
-
*
|
|
2977
|
-
* @beta
|
|
2978
3916
|
*/
|
|
2979
3917
|
static attachThumbnailCard(title, images, buttons, other) {
|
|
2980
3918
|
return MessageBuilder.attachContent(botbuilder.CardFactory.thumbnailCard(title, images, buttons, other));
|
|
@@ -2983,8 +3921,6 @@ class MessageBuilder {
|
|
|
2983
3921
|
* Add an attachement to a bot activity.
|
|
2984
3922
|
* @param attachement The attachment object to attach.
|
|
2985
3923
|
* @returns A message activity with an attachment.
|
|
2986
|
-
*
|
|
2987
|
-
* @beta
|
|
2988
3924
|
*/
|
|
2989
3925
|
static attachContent(attachement) {
|
|
2990
3926
|
return {
|
|
@@ -2993,15 +3929,229 @@ class MessageBuilder {
|
|
|
2993
3929
|
}
|
|
2994
3930
|
}
|
|
2995
3931
|
|
|
3932
|
+
// Copyright (c) Microsoft Corporation.
|
|
3933
|
+
/**
|
|
3934
|
+
* Retrieve the OAuth Sign in Link to use in the MessagingExtensionResult Suggested Actions.
|
|
3935
|
+
* This method only work on MessageExtension with Query now.
|
|
3936
|
+
*
|
|
3937
|
+
* @param {OnBehalfOfCredentialAuthConfig} authConfig - User custom the message extension authentication configuration.
|
|
3938
|
+
* @param {initiateLoginEndpoint} initiateLoginEndpoint - Login page for Teams to redirect to.
|
|
3939
|
+
* @param {string | string[]} scopes - The list of scopes for which the token will have access.
|
|
3940
|
+
*
|
|
3941
|
+
* @returns SignIn link CardAction with 200 status code.
|
|
3942
|
+
*/
|
|
3943
|
+
function getSignInResponseForMessageExtensionWithAuthConfig(authConfig, initiateLoginEndpoint, scopes) {
|
|
3944
|
+
const scopesArray = getScopesArray(scopes);
|
|
3945
|
+
const signInLink = `${initiateLoginEndpoint}?scope=${encodeURI(scopesArray.join(" "))}&clientId=${authConfig.clientId}&tenantId=${authConfig.tenantId}`;
|
|
3946
|
+
return {
|
|
3947
|
+
composeExtension: {
|
|
3948
|
+
type: "silentAuth",
|
|
3949
|
+
suggestedActions: {
|
|
3950
|
+
actions: [
|
|
3951
|
+
{
|
|
3952
|
+
type: "openUrl",
|
|
3953
|
+
value: signInLink,
|
|
3954
|
+
title: "Message Extension OAuth",
|
|
3955
|
+
},
|
|
3956
|
+
],
|
|
3957
|
+
},
|
|
3958
|
+
},
|
|
3959
|
+
};
|
|
3960
|
+
}
|
|
3961
|
+
/**
|
|
3962
|
+
* Retrieve the OAuth Sign in Link to use in the MessagingExtensionResult Suggested Actions.
|
|
3963
|
+
* This method only work on MessageExtension with Query now.
|
|
3964
|
+
*
|
|
3965
|
+
* @param {TeamsFx} teamsfx - Used to provide configuration and auth.
|
|
3966
|
+
* @param {string | string[]} scopes - The list of scopes for which the token will have access.
|
|
3967
|
+
*
|
|
3968
|
+
* @returns SignIn link CardAction with 200 status code.
|
|
3969
|
+
*/
|
|
3970
|
+
function getSignInResponseForMessageExtension(teamsfx, scopes) {
|
|
3971
|
+
const scopesArray = getScopesArray(scopes);
|
|
3972
|
+
const signInLink = `${teamsfx.getConfig("initiateLoginEndpoint")}?scope=${encodeURI(scopesArray.join(" "))}&clientId=${teamsfx.getConfig("clientId")}&tenantId=${teamsfx.getConfig("tenantId")}`;
|
|
3973
|
+
return {
|
|
3974
|
+
composeExtension: {
|
|
3975
|
+
type: "silentAuth",
|
|
3976
|
+
suggestedActions: {
|
|
3977
|
+
actions: [
|
|
3978
|
+
{
|
|
3979
|
+
type: "openUrl",
|
|
3980
|
+
value: signInLink,
|
|
3981
|
+
title: "Message Extension OAuth",
|
|
3982
|
+
},
|
|
3983
|
+
],
|
|
3984
|
+
},
|
|
3985
|
+
},
|
|
3986
|
+
};
|
|
3987
|
+
}
|
|
3988
|
+
/**
|
|
3989
|
+
* execution in message extension with SSO token.
|
|
3990
|
+
*
|
|
3991
|
+
* @param {TurnContext} context - The context object for the current turn.
|
|
3992
|
+
* @param {OnBehalfOfCredentialAuthConfig} authConfig - User custom the message extension authentication configuration.
|
|
3993
|
+
* @param {initiateLoginEndpoint} initiateLoginEndpoint - Login page for Teams to redirect to.
|
|
3994
|
+
* @param {string[]} scopes - The list of scopes for which the token will have access.
|
|
3995
|
+
* @param {function} logic - Business logic when executing the query in message extension with SSO or access token.
|
|
3996
|
+
*
|
|
3997
|
+
* @throws {@link ErrorCode|InternalError} when failed to get access token with unknown error.
|
|
3998
|
+
* @throws {@link ErrorCode|TokenExpiredError} when SSO token has already expired.
|
|
3999
|
+
* @throws {@link ErrorCode|ServiceError} when failed to get access token from simple auth server.
|
|
4000
|
+
* @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
|
|
4001
|
+
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
|
|
4002
|
+
*
|
|
4003
|
+
* @returns A MessageExtension Response for the activity. If the logic not return any, return void instead.
|
|
4004
|
+
*/
|
|
4005
|
+
function executionWithTokenAndConfig(context, authConfig, initiateLoginEndpoint, scopes, logic) {
|
|
4006
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
4007
|
+
const valueObj = context.activity.value;
|
|
4008
|
+
if (!valueObj.authentication || !valueObj.authentication.token) {
|
|
4009
|
+
internalLogger.verbose("No AccessToken in request, return silentAuth for AccessToken");
|
|
4010
|
+
return getSignInResponseForMessageExtensionWithAuthConfig(authConfig, initiateLoginEndpoint, scopes);
|
|
4011
|
+
}
|
|
4012
|
+
try {
|
|
4013
|
+
const credential = new OnBehalfOfUserCredential(valueObj.authentication.token, authConfig);
|
|
4014
|
+
const token = yield credential.getToken(scopes);
|
|
4015
|
+
const ssoTokenExpiration = parseJwt(valueObj.authentication.token).exp;
|
|
4016
|
+
const tokenRes = {
|
|
4017
|
+
ssoToken: valueObj.authentication.token,
|
|
4018
|
+
ssoTokenExpiration: new Date(ssoTokenExpiration * 1000).toISOString(),
|
|
4019
|
+
token: token.token,
|
|
4020
|
+
expiration: token.expiresOnTimestamp.toString(),
|
|
4021
|
+
connectionName: "",
|
|
4022
|
+
};
|
|
4023
|
+
if (logic) {
|
|
4024
|
+
return yield logic(tokenRes);
|
|
4025
|
+
}
|
|
4026
|
+
}
|
|
4027
|
+
catch (err) {
|
|
4028
|
+
if (err instanceof ErrorWithCode && err.code === exports.ErrorCode.UiRequiredError) {
|
|
4029
|
+
internalLogger.verbose("User not consent yet, return 412 to user consent first.");
|
|
4030
|
+
const response = { status: 412 };
|
|
4031
|
+
yield context.sendActivity({ value: response, type: botbuilder.ActivityTypes.InvokeResponse });
|
|
4032
|
+
return;
|
|
4033
|
+
}
|
|
4034
|
+
throw err;
|
|
4035
|
+
}
|
|
4036
|
+
});
|
|
4037
|
+
}
|
|
4038
|
+
/**
|
|
4039
|
+
* execution in message extension with SSO token.
|
|
4040
|
+
*
|
|
4041
|
+
* @param {TurnContext} context - The context object for the current turn.
|
|
4042
|
+
* @param {AuthenticationConfiguration} config - User custom the message extension authentication configuration.
|
|
4043
|
+
* @param {string[]} scopes - The list of scopes for which the token will have access.
|
|
4044
|
+
* @param {function} logic - Business logic when executing the query in message extension with SSO or access token.
|
|
4045
|
+
*
|
|
4046
|
+
* @throws {@link ErrorCode|InternalError} when failed to get access token with unknown error.
|
|
4047
|
+
* @throws {@link ErrorCode|TokenExpiredError} when SSO token has already expired.
|
|
4048
|
+
* @throws {@link ErrorCode|ServiceError} when failed to get access token from simple auth server.
|
|
4049
|
+
* @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
|
|
4050
|
+
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
|
|
4051
|
+
*
|
|
4052
|
+
* @returns A MessageExtension Response for the activity. If the logic not return any, return void instead.
|
|
4053
|
+
*/
|
|
4054
|
+
function executionWithToken(context, config, scopes, logic) {
|
|
4055
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
4056
|
+
const valueObj = context.activity.value;
|
|
4057
|
+
if (!valueObj.authentication || !valueObj.authentication.token) {
|
|
4058
|
+
internalLogger.verbose("No AccessToken in request, return silentAuth for AccessToken");
|
|
4059
|
+
return getSignInResponseForMessageExtension(new TeamsFx(exports.IdentityType.User, config), scopes);
|
|
4060
|
+
}
|
|
4061
|
+
try {
|
|
4062
|
+
const teamsfx = new TeamsFx(exports.IdentityType.User, config).setSsoToken(valueObj.authentication.token);
|
|
4063
|
+
const token = yield teamsfx.getCredential().getToken(scopes);
|
|
4064
|
+
const ssoTokenExpiration = parseJwt(valueObj.authentication.token).exp;
|
|
4065
|
+
const tokenRes = {
|
|
4066
|
+
ssoToken: valueObj.authentication.token,
|
|
4067
|
+
ssoTokenExpiration: new Date(ssoTokenExpiration * 1000).toISOString(),
|
|
4068
|
+
token: token.token,
|
|
4069
|
+
expiration: token.expiresOnTimestamp.toString(),
|
|
4070
|
+
connectionName: "",
|
|
4071
|
+
};
|
|
4072
|
+
if (logic) {
|
|
4073
|
+
return yield logic(tokenRes);
|
|
4074
|
+
}
|
|
4075
|
+
}
|
|
4076
|
+
catch (err) {
|
|
4077
|
+
if (err instanceof ErrorWithCode && err.code === exports.ErrorCode.UiRequiredError) {
|
|
4078
|
+
internalLogger.verbose("User not consent yet, return 412 to user consent first.");
|
|
4079
|
+
const response = { status: 412 };
|
|
4080
|
+
yield context.sendActivity({ value: response, type: botbuilder.ActivityTypes.InvokeResponse });
|
|
4081
|
+
return;
|
|
4082
|
+
}
|
|
4083
|
+
throw err;
|
|
4084
|
+
}
|
|
4085
|
+
});
|
|
4086
|
+
}
|
|
4087
|
+
// eslint-disable-next-line no-secrets/no-secrets
|
|
4088
|
+
/**
|
|
4089
|
+
* Users execute query in message extension with SSO or access token.
|
|
4090
|
+
*
|
|
4091
|
+
*
|
|
4092
|
+
* @param {TurnContext} context - The context object for the current turn.
|
|
4093
|
+
* @param {AuthenticationConfiguration} config - User custom the message extension authentication configuration.
|
|
4094
|
+
* @param {string| string[]} scopes - The list of scopes for which the token will have access.
|
|
4095
|
+
* @param {function} logic - Business logic when executing the query in message extension with SSO or access token.
|
|
4096
|
+
*
|
|
4097
|
+
* @throws {@link ErrorCode|InternalError} when User invoke not response to message extension query.
|
|
4098
|
+
* @throws {@link ErrorCode|InternalError} when failed to get access token with unknown error.
|
|
4099
|
+
* @throws {@link ErrorCode|TokenExpiredError} when SSO token has already expired.
|
|
4100
|
+
* @throws {@link ErrorCode|ServiceError} when failed to get access token from simple auth server.
|
|
4101
|
+
* @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
|
|
4102
|
+
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
|
|
4103
|
+
*
|
|
4104
|
+
* @returns A MessageExtension Response for the activity. If the logic not return any, return void instead.
|
|
4105
|
+
*/
|
|
4106
|
+
function handleMessageExtensionQueryWithToken(context, config, scopes, logic) {
|
|
4107
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
4108
|
+
if (context.activity.name != "composeExtension/query") {
|
|
4109
|
+
internalLogger.error(ErrorMessage.OnlySupportInQueryActivity);
|
|
4110
|
+
throw new ErrorWithCode(formatString(ErrorMessage.OnlySupportInQueryActivity), exports.ErrorCode.FailedOperation);
|
|
4111
|
+
}
|
|
4112
|
+
return yield executionWithToken(context, config !== null && config !== void 0 ? config : {}, scopes, logic);
|
|
4113
|
+
});
|
|
4114
|
+
}
|
|
4115
|
+
/**
|
|
4116
|
+
* Users execute query in message extension with SSO or access token.
|
|
4117
|
+
*
|
|
4118
|
+
* @param {TurnContext} context - The context object for the current turn.
|
|
4119
|
+
* @param {OnBehalfOfCredentialAuthConfig} config - User custom the message extension authentication configuration.
|
|
4120
|
+
* @param {initiateLoginEndpoint} initiateLoginEndpoint - Login page for Teams to redirect to.
|
|
4121
|
+
* @param {string| string[]} scopes - The list of scopes for which the token will have access.
|
|
4122
|
+
* @param {function} logic - Business logic when executing the query in message extension with SSO or access token.
|
|
4123
|
+
*
|
|
4124
|
+
* @throws {@link ErrorCode|InternalError} when User invoke not response to message extension query.
|
|
4125
|
+
* @throws {@link ErrorCode|InternalError} when failed to get access token with unknown error.
|
|
4126
|
+
* @throws {@link ErrorCode|TokenExpiredError} when SSO token has already expired.
|
|
4127
|
+
* @throws {@link ErrorCode|ServiceError} when failed to get access token from simple auth server.
|
|
4128
|
+
* @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
|
|
4129
|
+
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
|
|
4130
|
+
*
|
|
4131
|
+
* @returns A MessageExtension Response for the activity. If the logic not return any, return void instead.
|
|
4132
|
+
*/
|
|
4133
|
+
function handleMessageExtensionQueryWithSSO(context, config, initiateLoginEndpoint, scopes, logic) {
|
|
4134
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
4135
|
+
if (context.activity.name != "composeExtension/query") {
|
|
4136
|
+
internalLogger.error(ErrorMessage.OnlySupportInQueryActivity);
|
|
4137
|
+
throw new ErrorWithCode(formatString(ErrorMessage.OnlySupportInQueryActivity), exports.ErrorCode.FailedOperation);
|
|
4138
|
+
}
|
|
4139
|
+
return yield executionWithTokenAndConfig(context, config !== null && config !== void 0 ? config : {}, initiateLoginEndpoint, scopes, logic);
|
|
4140
|
+
});
|
|
4141
|
+
}
|
|
4142
|
+
|
|
2996
4143
|
exports.ApiKeyProvider = ApiKeyProvider;
|
|
2997
4144
|
exports.AppCredential = AppCredential;
|
|
2998
4145
|
exports.BasicAuthProvider = BasicAuthProvider;
|
|
2999
4146
|
exports.BearerTokenAuthProvider = BearerTokenAuthProvider;
|
|
4147
|
+
exports.BotSsoExecutionDialog = BotSsoExecutionDialog;
|
|
4148
|
+
exports.CardActionBot = CardActionBot;
|
|
3000
4149
|
exports.CertificateAuthProvider = CertificateAuthProvider;
|
|
3001
4150
|
exports.Channel = Channel;
|
|
3002
4151
|
exports.CommandBot = CommandBot;
|
|
3003
4152
|
exports.ConversationBot = ConversationBot;
|
|
3004
4153
|
exports.ErrorWithCode = ErrorWithCode;
|
|
4154
|
+
exports.InvokeResponseFactory = InvokeResponseFactory;
|
|
3005
4155
|
exports.Member = Member;
|
|
3006
4156
|
exports.MessageBuilder = MessageBuilder;
|
|
3007
4157
|
exports.MsGraphAuthProvider = MsGraphAuthProvider;
|
|
@@ -3013,10 +4163,13 @@ exports.TeamsFx = TeamsFx;
|
|
|
3013
4163
|
exports.TeamsUserCredential = TeamsUserCredential;
|
|
3014
4164
|
exports.createApiClient = createApiClient;
|
|
3015
4165
|
exports.createMicrosoftGraphClient = createMicrosoftGraphClient;
|
|
4166
|
+
exports.createMicrosoftGraphClientWithCredential = createMicrosoftGraphClientWithCredential;
|
|
3016
4167
|
exports.createPemCertOption = createPemCertOption;
|
|
3017
4168
|
exports.createPfxCertOption = createPfxCertOption;
|
|
3018
4169
|
exports.getLogLevel = getLogLevel;
|
|
3019
4170
|
exports.getTediousConnectionConfig = getTediousConnectionConfig;
|
|
4171
|
+
exports.handleMessageExtensionQueryWithSSO = handleMessageExtensionQueryWithSSO;
|
|
4172
|
+
exports.handleMessageExtensionQueryWithToken = handleMessageExtensionQueryWithToken;
|
|
3020
4173
|
exports.sendAdaptiveCard = sendAdaptiveCard;
|
|
3021
4174
|
exports.sendMessage = sendMessage;
|
|
3022
4175
|
exports.setLogFunction = setLogFunction;
|