@microsoft/teamsfx 1.1.2-alpha.062e4a5ea.0 → 1.1.2-alpha.16418f119.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/dist/index.esm2017.js +293 -20
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +1099 -124
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +309 -20
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +1142 -123
- package/dist/index.node.cjs.js.map +1 -1
- package/package.json +8 -5
- package/types/teamsfx.d.ts +579 -23
package/dist/index.node.cjs.js
CHANGED
|
@@ -69,6 +69,30 @@ exports.ErrorCode = void 0;
|
|
|
69
69
|
* Channel is not supported error.
|
|
70
70
|
*/
|
|
71
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";
|
|
72
96
|
/**
|
|
73
97
|
* Runtime is not supported error.
|
|
74
98
|
*/
|
|
@@ -124,6 +148,15 @@ ErrorMessage.NodejsRuntimeNotSupported = "{0} is not supported in Node.";
|
|
|
124
148
|
ErrorMessage.FailToAcquireTokenOnBehalfOfUser = "Failed to acquire access token on behalf of user: {0}";
|
|
125
149
|
// ChannelNotSupported Error
|
|
126
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";
|
|
127
160
|
// IdentityTypeNotSupported Error
|
|
128
161
|
ErrorMessage.IdentityTypeNotSupported = "{0} identity is not supported in {1}";
|
|
129
162
|
// AuthorizationInfoError
|
|
@@ -134,6 +167,7 @@ ErrorMessage.EmptyParameter = "Parameter {0} is empty";
|
|
|
134
167
|
ErrorMessage.DuplicateHttpsOptionProperty = "Axios HTTPS agent already defined value for property {0}";
|
|
135
168
|
ErrorMessage.DuplicateApiKeyInHeader = "The request already defined api key in request header with name {0}.";
|
|
136
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.";
|
|
137
171
|
/**
|
|
138
172
|
* Error class with code and message thrown by the SDK.
|
|
139
173
|
*/
|
|
@@ -728,10 +762,13 @@ class TeamsUserCredential {
|
|
|
728
762
|
}
|
|
729
763
|
/**
|
|
730
764
|
* Popup login page to get user's access token with specific scopes.
|
|
765
|
+
*
|
|
766
|
+
* @param {string[]} resources - The optional list of resources for full trust Teams apps.
|
|
767
|
+
*
|
|
731
768
|
* @remarks
|
|
732
769
|
* Can only be used within Teams.
|
|
733
770
|
*/
|
|
734
|
-
login(scopes) {
|
|
771
|
+
login(scopes, resources) {
|
|
735
772
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
736
773
|
throw new ErrorWithCode(formatString(ErrorMessage.NodejsRuntimeNotSupported, "TeamsUserCredential"), exports.ErrorCode.RuntimeNotSupported);
|
|
737
774
|
});
|
|
@@ -748,10 +785,13 @@ class TeamsUserCredential {
|
|
|
748
785
|
}
|
|
749
786
|
/**
|
|
750
787
|
* Get basic user info from SSO token
|
|
788
|
+
*
|
|
789
|
+
* @param {string[]} resources - The optional list of resources for full trust Teams apps.
|
|
790
|
+
*
|
|
751
791
|
* @remarks
|
|
752
792
|
* Can only be used within Teams.
|
|
753
793
|
*/
|
|
754
|
-
getUserInfo() {
|
|
794
|
+
getUserInfo(resources) {
|
|
755
795
|
throw new ErrorWithCode(formatString(ErrorMessage.NodejsRuntimeNotSupported, "TeamsUserCredential"), exports.ErrorCode.RuntimeNotSupported);
|
|
756
796
|
}
|
|
757
797
|
}
|
|
@@ -1723,8 +1763,9 @@ class TeamsFx {
|
|
|
1723
1763
|
this.configuration = new Map();
|
|
1724
1764
|
this.loadFromEnv();
|
|
1725
1765
|
if (customConfig) {
|
|
1726
|
-
|
|
1727
|
-
|
|
1766
|
+
const myConfig = Object.assign({}, customConfig);
|
|
1767
|
+
for (const key of Object.keys(myConfig)) {
|
|
1768
|
+
const value = myConfig[key];
|
|
1728
1769
|
if (value) {
|
|
1729
1770
|
this.configuration.set(key, value);
|
|
1730
1771
|
}
|
|
@@ -1766,9 +1807,10 @@ class TeamsFx {
|
|
|
1766
1807
|
}
|
|
1767
1808
|
/**
|
|
1768
1809
|
* Get user information.
|
|
1810
|
+
* @param {string[]} resources - The optional list of resources for full trust Teams apps.
|
|
1769
1811
|
* @returns UserInfo object.
|
|
1770
1812
|
*/
|
|
1771
|
-
getUserInfo() {
|
|
1813
|
+
getUserInfo(resources) {
|
|
1772
1814
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
1773
1815
|
if (this.identityType !== exports.IdentityType.User) {
|
|
1774
1816
|
const errorMsg = formatString(ErrorMessage.IdentityTypeNotSupported, this.identityType.toString(), "TeamsFx");
|
|
@@ -1792,13 +1834,14 @@ class TeamsFx {
|
|
|
1792
1834
|
* await teamsfx.login("https://graph.microsoft.com/User.Read Calendars.Read"); // multiple scopes using string
|
|
1793
1835
|
* ```
|
|
1794
1836
|
* @param scopes - The list of scopes for which the token will have access, before that, we will request user to consent.
|
|
1837
|
+
* @param {string[]} resources - The optional list of resources for full trust Teams apps.
|
|
1795
1838
|
*
|
|
1796
1839
|
* @throws {@link ErrorCode|InternalError} when failed to login with unknown error.
|
|
1797
1840
|
* @throws {@link ErrorCode|ConsentFailed} when user canceled or failed to consent.
|
|
1798
1841
|
* @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
|
|
1799
1842
|
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
|
|
1800
1843
|
*/
|
|
1801
|
-
login(scopes) {
|
|
1844
|
+
login(scopes, resources) {
|
|
1802
1845
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
1803
1846
|
throw new ErrorWithCode(formatString(ErrorMessage.NodejsRuntimeNotSupported, "login"), exports.ErrorCode.RuntimeNotSupported);
|
|
1804
1847
|
});
|
|
@@ -1904,7 +1947,468 @@ exports.NotificationTargetType = void 0;
|
|
|
1904
1947
|
* The notification will be sent to a personal chat.
|
|
1905
1948
|
*/
|
|
1906
1949
|
NotificationTargetType["Person"] = "Person";
|
|
1907
|
-
})(exports.NotificationTargetType || (exports.NotificationTargetType = {}));
|
|
1950
|
+
})(exports.NotificationTargetType || (exports.NotificationTargetType = {}));
|
|
1951
|
+
/**
|
|
1952
|
+
* Options used to control how the response card will be sent to users.
|
|
1953
|
+
*/
|
|
1954
|
+
exports.AdaptiveCardResponse = void 0;
|
|
1955
|
+
(function (AdaptiveCardResponse) {
|
|
1956
|
+
/**
|
|
1957
|
+
* The response card will be replaced the current one for the interactor who trigger the action.
|
|
1958
|
+
*/
|
|
1959
|
+
AdaptiveCardResponse[AdaptiveCardResponse["ReplaceForInteractor"] = 0] = "ReplaceForInteractor";
|
|
1960
|
+
/**
|
|
1961
|
+
* The response card will be replaced the current one for all users in the chat.
|
|
1962
|
+
*/
|
|
1963
|
+
AdaptiveCardResponse[AdaptiveCardResponse["ReplaceForAll"] = 1] = "ReplaceForAll";
|
|
1964
|
+
/**
|
|
1965
|
+
* The response card will be sent as a new message for all users in the chat.
|
|
1966
|
+
*/
|
|
1967
|
+
AdaptiveCardResponse[AdaptiveCardResponse["NewForAll"] = 2] = "NewForAll";
|
|
1968
|
+
})(exports.AdaptiveCardResponse || (exports.AdaptiveCardResponse = {}));
|
|
1969
|
+
/**
|
|
1970
|
+
* Status code for an `application/vnd.microsoft.error` invoke response.
|
|
1971
|
+
*/
|
|
1972
|
+
exports.InvokeResponseErrorCode = void 0;
|
|
1973
|
+
(function (InvokeResponseErrorCode) {
|
|
1974
|
+
/**
|
|
1975
|
+
* Invalid request.
|
|
1976
|
+
*/
|
|
1977
|
+
InvokeResponseErrorCode[InvokeResponseErrorCode["BadRequest"] = 400] = "BadRequest";
|
|
1978
|
+
/**
|
|
1979
|
+
* Internal server error.
|
|
1980
|
+
*/
|
|
1981
|
+
InvokeResponseErrorCode[InvokeResponseErrorCode["InternalServerError"] = 500] = "InternalServerError";
|
|
1982
|
+
})(exports.InvokeResponseErrorCode || (exports.InvokeResponseErrorCode = {}));
|
|
1983
|
+
|
|
1984
|
+
/**
|
|
1985
|
+
* Available response type for an adaptive card invoke response.
|
|
1986
|
+
* @internal
|
|
1987
|
+
*/
|
|
1988
|
+
var InvokeResponseType;
|
|
1989
|
+
(function (InvokeResponseType) {
|
|
1990
|
+
InvokeResponseType["AdaptiveCard"] = "application/vnd.microsoft.card.adaptive";
|
|
1991
|
+
InvokeResponseType["Message"] = "application/vnd.microsoft.activity.message";
|
|
1992
|
+
InvokeResponseType["Error"] = "application/vnd.microsoft.error";
|
|
1993
|
+
})(InvokeResponseType || (InvokeResponseType = {}));
|
|
1994
|
+
/**
|
|
1995
|
+
* Provides methods for formatting various invoke responses a bot can send to respond to an invoke request.
|
|
1996
|
+
*
|
|
1997
|
+
* @remarks
|
|
1998
|
+
* All of these functions return an {@link InvokeResponse} object, which can be
|
|
1999
|
+
* passed as input to generate a new `invokeResponse` activity.
|
|
2000
|
+
*
|
|
2001
|
+
* This example sends an invoke response that contains an adaptive card.
|
|
2002
|
+
*
|
|
2003
|
+
* ```typescript
|
|
2004
|
+
*
|
|
2005
|
+
* const myCard: IAdaptiveCard = {
|
|
2006
|
+
* type: "AdaptiveCard",
|
|
2007
|
+
* body: [
|
|
2008
|
+
* {
|
|
2009
|
+
* "type": "TextBlock",
|
|
2010
|
+
* "text": "This is a sample card"
|
|
2011
|
+
* }],
|
|
2012
|
+
* $schema: "http://adaptivecards.io/schemas/adaptive-card.json",
|
|
2013
|
+
* version: "1.4"
|
|
2014
|
+
* };
|
|
2015
|
+
*
|
|
2016
|
+
* const invokeResponse = InvokeResponseFactory.adaptiveCard(myCard);
|
|
2017
|
+
* await context.sendActivity({
|
|
2018
|
+
* type: ActivityTypes.InvokeResponse,
|
|
2019
|
+
* value: invokeResponse,
|
|
2020
|
+
* });
|
|
2021
|
+
* ```
|
|
2022
|
+
*/
|
|
2023
|
+
class InvokeResponseFactory {
|
|
2024
|
+
/**
|
|
2025
|
+
* Create an invoke response from a text message.
|
|
2026
|
+
* The type of the invoke response is `application/vnd.microsoft.activity.message`
|
|
2027
|
+
* indicates the request was successfully processed.
|
|
2028
|
+
*
|
|
2029
|
+
* @param message A text message included in a invoke response.
|
|
2030
|
+
*
|
|
2031
|
+
* @returns {InvokeResponse} An InvokeResponse object.
|
|
2032
|
+
*/
|
|
2033
|
+
static textMessage(message) {
|
|
2034
|
+
if (!message) {
|
|
2035
|
+
throw new Error("The text message cannot be null or empty");
|
|
2036
|
+
}
|
|
2037
|
+
return {
|
|
2038
|
+
status: botbuilder.StatusCodes.OK,
|
|
2039
|
+
body: {
|
|
2040
|
+
statusCode: botbuilder.StatusCodes.OK,
|
|
2041
|
+
type: InvokeResponseType.Message,
|
|
2042
|
+
value: message,
|
|
2043
|
+
},
|
|
2044
|
+
};
|
|
2045
|
+
}
|
|
2046
|
+
/**
|
|
2047
|
+
* Create an invoke response from an adaptive card.
|
|
2048
|
+
*
|
|
2049
|
+
* The type of the invoke response is `application/vnd.microsoft.card.adaptive` indicates
|
|
2050
|
+
* the request was successfully processed, and the response includes an adaptive card
|
|
2051
|
+
* that the client should display in place of the current one.
|
|
2052
|
+
*
|
|
2053
|
+
* @param card The adaptive card JSON payload.
|
|
2054
|
+
*
|
|
2055
|
+
* @returns {InvokeResponse} An InvokeResponse object.
|
|
2056
|
+
*/
|
|
2057
|
+
static adaptiveCard(card) {
|
|
2058
|
+
if (!card) {
|
|
2059
|
+
throw new Error("The adaptive card content cannot be null or undefined");
|
|
2060
|
+
}
|
|
2061
|
+
return {
|
|
2062
|
+
status: botbuilder.StatusCodes.OK,
|
|
2063
|
+
body: {
|
|
2064
|
+
statusCode: botbuilder.StatusCodes.OK,
|
|
2065
|
+
type: InvokeResponseType.AdaptiveCard,
|
|
2066
|
+
value: card,
|
|
2067
|
+
},
|
|
2068
|
+
};
|
|
2069
|
+
}
|
|
2070
|
+
/**
|
|
2071
|
+
* Create an invoke response with error code and message.
|
|
2072
|
+
*
|
|
2073
|
+
* The type of the invoke response is `application/vnd.microsoft.error` indicates
|
|
2074
|
+
* the request was failed to processed.
|
|
2075
|
+
*
|
|
2076
|
+
* @param errorCode The status code indicates error, available values:
|
|
2077
|
+
* - 400 (BadRequest): indicate the incoming request was invalid.
|
|
2078
|
+
* - 500 (InternalServerError): indicate an unexpected error occurred.
|
|
2079
|
+
* @param errorMessage The error message.
|
|
2080
|
+
*
|
|
2081
|
+
* @returns {InvokeResponse} An InvokeResponse object.
|
|
2082
|
+
*/
|
|
2083
|
+
static errorResponse(errorCode, errorMessage) {
|
|
2084
|
+
return {
|
|
2085
|
+
status: botbuilder.StatusCodes.OK,
|
|
2086
|
+
body: {
|
|
2087
|
+
statusCode: errorCode,
|
|
2088
|
+
type: InvokeResponseType.Error,
|
|
2089
|
+
value: {
|
|
2090
|
+
code: errorCode.toString(),
|
|
2091
|
+
message: errorMessage,
|
|
2092
|
+
},
|
|
2093
|
+
},
|
|
2094
|
+
};
|
|
2095
|
+
}
|
|
2096
|
+
/**
|
|
2097
|
+
* Create an invoke response with status code and response value.
|
|
2098
|
+
* @param statusCode The status code.
|
|
2099
|
+
* @param body The value of the response body.
|
|
2100
|
+
*
|
|
2101
|
+
* @returns {InvokeResponse} An InvokeResponse object.
|
|
2102
|
+
*/
|
|
2103
|
+
static createInvokeResponse(statusCode, body) {
|
|
2104
|
+
return {
|
|
2105
|
+
status: statusCode,
|
|
2106
|
+
body: body,
|
|
2107
|
+
};
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
|
|
2111
|
+
/**
|
|
2112
|
+
* @internal
|
|
2113
|
+
*/
|
|
2114
|
+
class CardActionMiddleware {
|
|
2115
|
+
constructor(handlers) {
|
|
2116
|
+
this.actionHandlers = [];
|
|
2117
|
+
this.defaultMessage = "Your response was sent to the app";
|
|
2118
|
+
if (handlers && handlers.length > 0) {
|
|
2119
|
+
this.actionHandlers.push(...handlers);
|
|
2120
|
+
}
|
|
2121
|
+
}
|
|
2122
|
+
onTurn(context, next) {
|
|
2123
|
+
var _a, _b, _c;
|
|
2124
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2125
|
+
if (context.activity.name === "adaptiveCard/action") {
|
|
2126
|
+
const action = context.activity.value.action;
|
|
2127
|
+
const actionVerb = action.verb;
|
|
2128
|
+
for (const handler of this.actionHandlers) {
|
|
2129
|
+
if (((_a = handler.triggerVerb) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === (actionVerb === null || actionVerb === void 0 ? void 0 : actionVerb.toLowerCase())) {
|
|
2130
|
+
let response;
|
|
2131
|
+
try {
|
|
2132
|
+
response = yield handler.handleActionInvoked(context, action.data);
|
|
2133
|
+
}
|
|
2134
|
+
catch (error) {
|
|
2135
|
+
const errorResponse = InvokeResponseFactory.errorResponse(exports.InvokeResponseErrorCode.InternalServerError, error.message);
|
|
2136
|
+
yield this.sendInvokeResponse(context, errorResponse);
|
|
2137
|
+
throw error;
|
|
2138
|
+
}
|
|
2139
|
+
const responseType = (_b = response.body) === null || _b === void 0 ? void 0 : _b.type;
|
|
2140
|
+
switch (responseType) {
|
|
2141
|
+
case InvokeResponseType.AdaptiveCard:
|
|
2142
|
+
const card = (_c = response.body) === null || _c === void 0 ? void 0 : _c.value;
|
|
2143
|
+
if (!card) {
|
|
2144
|
+
const errorMessage = "Adaptive card content cannot be found in the response body";
|
|
2145
|
+
yield this.sendInvokeResponse(context, InvokeResponseFactory.errorResponse(exports.InvokeResponseErrorCode.InternalServerError, errorMessage));
|
|
2146
|
+
throw new Error(errorMessage);
|
|
2147
|
+
}
|
|
2148
|
+
if (card.refresh && handler.adaptiveCardResponse !== exports.AdaptiveCardResponse.NewForAll) {
|
|
2149
|
+
// Card won't be refreshed with AdaptiveCardResponse.ReplaceForInteractor.
|
|
2150
|
+
// So set to AdaptiveCardResponse.ReplaceForAll here.
|
|
2151
|
+
handler.adaptiveCardResponse = exports.AdaptiveCardResponse.ReplaceForAll;
|
|
2152
|
+
}
|
|
2153
|
+
const activity = botbuilder.MessageFactory.attachment(botbuilder.CardFactory.adaptiveCard(card));
|
|
2154
|
+
if (handler.adaptiveCardResponse === exports.AdaptiveCardResponse.NewForAll) {
|
|
2155
|
+
yield this.sendInvokeResponse(context, InvokeResponseFactory.textMessage(this.defaultMessage));
|
|
2156
|
+
yield context.sendActivity(activity);
|
|
2157
|
+
}
|
|
2158
|
+
else if (handler.adaptiveCardResponse === exports.AdaptiveCardResponse.ReplaceForAll) {
|
|
2159
|
+
activity.id = context.activity.replyToId;
|
|
2160
|
+
yield context.updateActivity(activity);
|
|
2161
|
+
yield this.sendInvokeResponse(context, response);
|
|
2162
|
+
}
|
|
2163
|
+
else {
|
|
2164
|
+
yield this.sendInvokeResponse(context, response);
|
|
2165
|
+
}
|
|
2166
|
+
break;
|
|
2167
|
+
case InvokeResponseType.Message:
|
|
2168
|
+
case InvokeResponseType.Error:
|
|
2169
|
+
default:
|
|
2170
|
+
yield this.sendInvokeResponse(context, response);
|
|
2171
|
+
break;
|
|
2172
|
+
}
|
|
2173
|
+
break;
|
|
2174
|
+
}
|
|
2175
|
+
}
|
|
2176
|
+
}
|
|
2177
|
+
yield next();
|
|
2178
|
+
});
|
|
2179
|
+
}
|
|
2180
|
+
sendInvokeResponse(context, response) {
|
|
2181
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2182
|
+
yield context.sendActivity({
|
|
2183
|
+
type: botbuilder.ActivityTypes.InvokeResponse,
|
|
2184
|
+
value: response,
|
|
2185
|
+
});
|
|
2186
|
+
});
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
|
|
2190
|
+
/**
|
|
2191
|
+
* A card action bot to respond to adaptive card universal actions.
|
|
2192
|
+
*/
|
|
2193
|
+
class CardActionBot {
|
|
2194
|
+
/**
|
|
2195
|
+
* Creates a new instance of the `CardActionBot`.
|
|
2196
|
+
*
|
|
2197
|
+
* @param adapter The bound `BotFrameworkAdapter`.
|
|
2198
|
+
* @param options - initialize options
|
|
2199
|
+
*/
|
|
2200
|
+
constructor(adapter, options) {
|
|
2201
|
+
this.middleware = new CardActionMiddleware(options === null || options === void 0 ? void 0 : options.actions);
|
|
2202
|
+
this.adapter = adapter.use(this.middleware);
|
|
2203
|
+
}
|
|
2204
|
+
/**
|
|
2205
|
+
* Registers a card action handler to the bot.
|
|
2206
|
+
* @param actionHandler A card action handler to be registered.
|
|
2207
|
+
*/
|
|
2208
|
+
registerHandler(actionHandler) {
|
|
2209
|
+
if (actionHandler) {
|
|
2210
|
+
this.middleware.actionHandlers.push(actionHandler);
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
/**
|
|
2214
|
+
* Registers card action handlers to the bot.
|
|
2215
|
+
* @param actionHandlers A set of card action handlers to be registered.
|
|
2216
|
+
*/
|
|
2217
|
+
registerHandlers(actionHandlers) {
|
|
2218
|
+
if (actionHandlers) {
|
|
2219
|
+
this.middleware.actionHandlers.push(...actionHandlers);
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
}
|
|
2223
|
+
|
|
2224
|
+
// Copyright (c) Microsoft Corporation.
|
|
2225
|
+
/**
|
|
2226
|
+
* @internal
|
|
2227
|
+
*/
|
|
2228
|
+
class CommandResponseMiddleware {
|
|
2229
|
+
constructor(handlers, ssoHandlers, activityHandler) {
|
|
2230
|
+
this.commandHandlers = [];
|
|
2231
|
+
this.ssoCommandHandlers = [];
|
|
2232
|
+
handlers = handlers !== null && handlers !== void 0 ? handlers : [];
|
|
2233
|
+
ssoHandlers = ssoHandlers !== null && ssoHandlers !== void 0 ? ssoHandlers : [];
|
|
2234
|
+
this.hasSsoCommand = ssoHandlers.length > 0;
|
|
2235
|
+
this.ssoActivityHandler = activityHandler;
|
|
2236
|
+
if (this.hasSsoCommand && !this.ssoActivityHandler) {
|
|
2237
|
+
internalLogger.error(ErrorMessage.SsoActivityHandlerIsNull);
|
|
2238
|
+
throw new ErrorWithCode(ErrorMessage.SsoActivityHandlerIsNull, exports.ErrorCode.SsoActivityHandlerIsUndefined);
|
|
2239
|
+
}
|
|
2240
|
+
this.commandHandlers.push(...handlers);
|
|
2241
|
+
for (const ssoHandler of ssoHandlers) {
|
|
2242
|
+
this.addSsoCommand(ssoHandler);
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2245
|
+
addSsoCommand(ssoHandler) {
|
|
2246
|
+
var _a;
|
|
2247
|
+
(_a = this.ssoActivityHandler) === null || _a === void 0 ? void 0 : _a.addCommand((context, tokenResponse, message) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2248
|
+
const matchResult = this.shouldTrigger(ssoHandler.triggerPatterns, message.text);
|
|
2249
|
+
message.matches = Array.isArray(matchResult) ? matchResult : void 0;
|
|
2250
|
+
const response = yield ssoHandler.handleCommandReceived(context, message, tokenResponse);
|
|
2251
|
+
yield this.processResponse(context, response);
|
|
2252
|
+
}), ssoHandler.triggerPatterns);
|
|
2253
|
+
this.ssoCommandHandlers.push(ssoHandler);
|
|
2254
|
+
this.hasSsoCommand = true;
|
|
2255
|
+
}
|
|
2256
|
+
onTurn(context, next) {
|
|
2257
|
+
var _a, _b;
|
|
2258
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2259
|
+
if (context.activity.type === botbuilder.ActivityTypes.Message) {
|
|
2260
|
+
// Invoke corresponding command handler for the command response
|
|
2261
|
+
const commandText = this.getActivityText(context.activity);
|
|
2262
|
+
let alreadyProcessed = false;
|
|
2263
|
+
for (const handler of this.commandHandlers) {
|
|
2264
|
+
const matchResult = this.shouldTrigger(handler.triggerPatterns, commandText);
|
|
2265
|
+
// It is important to note that the command bot will stop processing handlers
|
|
2266
|
+
// when the first command handler is matched.
|
|
2267
|
+
if (!!matchResult) {
|
|
2268
|
+
const message = {
|
|
2269
|
+
text: commandText,
|
|
2270
|
+
};
|
|
2271
|
+
message.matches = Array.isArray(matchResult) ? matchResult : void 0;
|
|
2272
|
+
const response = yield handler.handleCommandReceived(context, message);
|
|
2273
|
+
yield this.processResponse(context, response);
|
|
2274
|
+
alreadyProcessed = true;
|
|
2275
|
+
break;
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
if (!alreadyProcessed) {
|
|
2279
|
+
for (const handler of this.ssoCommandHandlers) {
|
|
2280
|
+
const matchResult = this.shouldTrigger(handler.triggerPatterns, commandText);
|
|
2281
|
+
if (!!matchResult) {
|
|
2282
|
+
yield ((_a = this.ssoActivityHandler) === null || _a === void 0 ? void 0 : _a.run(context));
|
|
2283
|
+
break;
|
|
2284
|
+
}
|
|
2285
|
+
}
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
else {
|
|
2289
|
+
if (this.hasSsoCommand) {
|
|
2290
|
+
yield ((_b = this.ssoActivityHandler) === null || _b === void 0 ? void 0 : _b.run(context));
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
yield next();
|
|
2294
|
+
});
|
|
2295
|
+
}
|
|
2296
|
+
processResponse(context, response) {
|
|
2297
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2298
|
+
if (typeof response === "string") {
|
|
2299
|
+
yield context.sendActivity(response);
|
|
2300
|
+
}
|
|
2301
|
+
else {
|
|
2302
|
+
const replyActivity = response;
|
|
2303
|
+
if (replyActivity) {
|
|
2304
|
+
yield context.sendActivity(replyActivity);
|
|
2305
|
+
}
|
|
2306
|
+
}
|
|
2307
|
+
});
|
|
2308
|
+
}
|
|
2309
|
+
matchPattern(pattern, text) {
|
|
2310
|
+
if (text) {
|
|
2311
|
+
if (typeof pattern === "string") {
|
|
2312
|
+
const regExp = new RegExp(pattern, "i");
|
|
2313
|
+
return regExp.test(text);
|
|
2314
|
+
}
|
|
2315
|
+
if (pattern instanceof RegExp) {
|
|
2316
|
+
const matches = text.match(pattern);
|
|
2317
|
+
return matches !== null && matches !== void 0 ? matches : false;
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
return false;
|
|
2321
|
+
}
|
|
2322
|
+
shouldTrigger(patterns, text) {
|
|
2323
|
+
const expressions = Array.isArray(patterns) ? patterns : [patterns];
|
|
2324
|
+
for (const ex of expressions) {
|
|
2325
|
+
const arg = this.matchPattern(ex, text);
|
|
2326
|
+
if (arg)
|
|
2327
|
+
return arg;
|
|
2328
|
+
}
|
|
2329
|
+
return false;
|
|
2330
|
+
}
|
|
2331
|
+
getActivityText(activity) {
|
|
2332
|
+
let text = activity.text;
|
|
2333
|
+
const removedMentionText = botbuilder.TurnContext.removeRecipientMention(activity);
|
|
2334
|
+
if (removedMentionText) {
|
|
2335
|
+
text = removedMentionText
|
|
2336
|
+
.toLowerCase()
|
|
2337
|
+
.replace(/\n|\r\n/g, "")
|
|
2338
|
+
.trim();
|
|
2339
|
+
}
|
|
2340
|
+
return text;
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
|
|
2344
|
+
// Copyright (c) Microsoft Corporation.
|
|
2345
|
+
/**
|
|
2346
|
+
* A command bot for receiving commands and sending responses in Teams.
|
|
2347
|
+
*
|
|
2348
|
+
* @remarks
|
|
2349
|
+
* 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.
|
|
2350
|
+
*/
|
|
2351
|
+
class CommandBot {
|
|
2352
|
+
/**
|
|
2353
|
+
* Creates a new instance of the `CommandBot`.
|
|
2354
|
+
*
|
|
2355
|
+
* @param adapter The bound `BotFrameworkAdapter`.
|
|
2356
|
+
* @param options - initialize options
|
|
2357
|
+
*/
|
|
2358
|
+
constructor(adapter, options, ssoCommandActivityHandler, ssoConfig) {
|
|
2359
|
+
this.ssoConfig = ssoConfig;
|
|
2360
|
+
this.middleware = new CommandResponseMiddleware(options === null || options === void 0 ? void 0 : options.commands, options === null || options === void 0 ? void 0 : options.ssoCommands, ssoCommandActivityHandler);
|
|
2361
|
+
this.adapter = adapter.use(this.middleware);
|
|
2362
|
+
}
|
|
2363
|
+
/**
|
|
2364
|
+
* Registers a command into the command bot.
|
|
2365
|
+
*
|
|
2366
|
+
* @param command The command to register.
|
|
2367
|
+
*/
|
|
2368
|
+
registerCommand(command) {
|
|
2369
|
+
if (command) {
|
|
2370
|
+
this.middleware.commandHandlers.push(command);
|
|
2371
|
+
}
|
|
2372
|
+
}
|
|
2373
|
+
/**
|
|
2374
|
+
* Registers commands into the command bot.
|
|
2375
|
+
*
|
|
2376
|
+
* @param commands The commands to register.
|
|
2377
|
+
*/
|
|
2378
|
+
registerCommands(commands) {
|
|
2379
|
+
if (commands) {
|
|
2380
|
+
this.middleware.commandHandlers.push(...commands);
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2383
|
+
/**
|
|
2384
|
+
* Registers a sso command into the command bot.
|
|
2385
|
+
*
|
|
2386
|
+
* @param command The command to register.
|
|
2387
|
+
*/
|
|
2388
|
+
registerSsoCommand(ssoCommand) {
|
|
2389
|
+
this.validateSsoActivityHandler();
|
|
2390
|
+
this.middleware.addSsoCommand(ssoCommand);
|
|
2391
|
+
}
|
|
2392
|
+
/**
|
|
2393
|
+
* Registers commands into the command bot.
|
|
2394
|
+
*
|
|
2395
|
+
* @param commands The commands to register.
|
|
2396
|
+
*/
|
|
2397
|
+
registerSsoCommands(ssoCommands) {
|
|
2398
|
+
if (ssoCommands.length > 0) {
|
|
2399
|
+
this.validateSsoActivityHandler();
|
|
2400
|
+
for (const ssoCommand of ssoCommands) {
|
|
2401
|
+
this.middleware.addSsoCommand(ssoCommand);
|
|
2402
|
+
}
|
|
2403
|
+
}
|
|
2404
|
+
}
|
|
2405
|
+
validateSsoActivityHandler() {
|
|
2406
|
+
if (!this.middleware.ssoActivityHandler) {
|
|
2407
|
+
internalLogger.error(ErrorMessage.SsoActivityHandlerIsNull);
|
|
2408
|
+
throw new ErrorWithCode(ErrorMessage.SsoActivityHandlerIsNull, exports.ErrorCode.SsoActivityHandlerIsUndefined);
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
}
|
|
1908
2412
|
|
|
1909
2413
|
// Copyright (c) Microsoft Corporation.
|
|
1910
2414
|
/**
|
|
@@ -2032,117 +2536,6 @@ class NotificationMiddleware {
|
|
|
2032
2536
|
}
|
|
2033
2537
|
});
|
|
2034
2538
|
}
|
|
2035
|
-
}
|
|
2036
|
-
class CommandResponseMiddleware {
|
|
2037
|
-
constructor(handlers) {
|
|
2038
|
-
this.commandHandlers = [];
|
|
2039
|
-
if (handlers && handlers.length > 0) {
|
|
2040
|
-
this.commandHandlers.push(...handlers);
|
|
2041
|
-
}
|
|
2042
|
-
}
|
|
2043
|
-
onTurn(context, next) {
|
|
2044
|
-
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2045
|
-
if (context.activity.type === botbuilder.ActivityTypes.Message) {
|
|
2046
|
-
// Invoke corresponding command handler for the command response
|
|
2047
|
-
const commandText = this.getActivityText(context.activity);
|
|
2048
|
-
const message = {
|
|
2049
|
-
text: commandText,
|
|
2050
|
-
};
|
|
2051
|
-
for (const handler of this.commandHandlers) {
|
|
2052
|
-
const matchResult = this.shouldTrigger(handler.triggerPatterns, commandText);
|
|
2053
|
-
// It is important to note that the command bot will stop processing handlers
|
|
2054
|
-
// when the first command handler is matched.
|
|
2055
|
-
if (!!matchResult) {
|
|
2056
|
-
message.matches = Array.isArray(matchResult) ? matchResult : void 0;
|
|
2057
|
-
const response = yield handler.handleCommandReceived(context, message);
|
|
2058
|
-
if (typeof response === "string") {
|
|
2059
|
-
yield context.sendActivity(response);
|
|
2060
|
-
}
|
|
2061
|
-
else {
|
|
2062
|
-
const replyActivity = response;
|
|
2063
|
-
if (replyActivity) {
|
|
2064
|
-
yield context.sendActivity(replyActivity);
|
|
2065
|
-
}
|
|
2066
|
-
}
|
|
2067
|
-
}
|
|
2068
|
-
}
|
|
2069
|
-
}
|
|
2070
|
-
yield next();
|
|
2071
|
-
});
|
|
2072
|
-
}
|
|
2073
|
-
matchPattern(pattern, text) {
|
|
2074
|
-
if (text) {
|
|
2075
|
-
if (typeof pattern === "string") {
|
|
2076
|
-
const regExp = new RegExp(pattern, "i");
|
|
2077
|
-
return regExp.test(text);
|
|
2078
|
-
}
|
|
2079
|
-
if (pattern instanceof RegExp) {
|
|
2080
|
-
const matches = text.match(pattern);
|
|
2081
|
-
return matches !== null && matches !== void 0 ? matches : false;
|
|
2082
|
-
}
|
|
2083
|
-
}
|
|
2084
|
-
return false;
|
|
2085
|
-
}
|
|
2086
|
-
shouldTrigger(patterns, text) {
|
|
2087
|
-
const expressions = Array.isArray(patterns) ? patterns : [patterns];
|
|
2088
|
-
for (const ex of expressions) {
|
|
2089
|
-
const arg = this.matchPattern(ex, text);
|
|
2090
|
-
if (arg)
|
|
2091
|
-
return arg;
|
|
2092
|
-
}
|
|
2093
|
-
return false;
|
|
2094
|
-
}
|
|
2095
|
-
getActivityText(activity) {
|
|
2096
|
-
let text = activity.text;
|
|
2097
|
-
const removedMentionText = botbuilder.TurnContext.removeRecipientMention(activity);
|
|
2098
|
-
if (removedMentionText) {
|
|
2099
|
-
text = removedMentionText
|
|
2100
|
-
.toLowerCase()
|
|
2101
|
-
.replace(/\n|\r\n/g, "")
|
|
2102
|
-
.trim();
|
|
2103
|
-
}
|
|
2104
|
-
return text;
|
|
2105
|
-
}
|
|
2106
|
-
}
|
|
2107
|
-
|
|
2108
|
-
// Copyright (c) Microsoft Corporation.
|
|
2109
|
-
/**
|
|
2110
|
-
* A command bot for receiving commands and sending responses in Teams.
|
|
2111
|
-
*
|
|
2112
|
-
* @remarks
|
|
2113
|
-
* 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.
|
|
2114
|
-
*/
|
|
2115
|
-
class CommandBot {
|
|
2116
|
-
/**
|
|
2117
|
-
* Creates a new instance of the `CommandBot`.
|
|
2118
|
-
*
|
|
2119
|
-
* @param adapter The bound `BotFrameworkAdapter`.
|
|
2120
|
-
* @param options - initialize options
|
|
2121
|
-
*/
|
|
2122
|
-
constructor(adapter, options) {
|
|
2123
|
-
this.middleware = new CommandResponseMiddleware(options === null || options === void 0 ? void 0 : options.commands);
|
|
2124
|
-
this.adapter = adapter.use(this.middleware);
|
|
2125
|
-
}
|
|
2126
|
-
/**
|
|
2127
|
-
* Registers a command into the command bot.
|
|
2128
|
-
*
|
|
2129
|
-
* @param command The command to registered.
|
|
2130
|
-
*/
|
|
2131
|
-
registerCommand(command) {
|
|
2132
|
-
if (command) {
|
|
2133
|
-
this.middleware.commandHandlers.push(command);
|
|
2134
|
-
}
|
|
2135
|
-
}
|
|
2136
|
-
/**
|
|
2137
|
-
* Registers commands into the command bot.
|
|
2138
|
-
*
|
|
2139
|
-
* @param commands The command to registered.
|
|
2140
|
-
*/
|
|
2141
|
-
registerCommands(commands) {
|
|
2142
|
-
if (commands) {
|
|
2143
|
-
this.middleware.commandHandlers.push(...commands);
|
|
2144
|
-
}
|
|
2145
|
-
}
|
|
2146
2539
|
}
|
|
2147
2540
|
|
|
2148
2541
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -2522,6 +2915,10 @@ class TeamsBotInstallation {
|
|
|
2522
2915
|
*/
|
|
2523
2916
|
channels() {
|
|
2524
2917
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2918
|
+
const channels = [];
|
|
2919
|
+
if (this.type !== exports.NotificationTargetType.Channel) {
|
|
2920
|
+
return channels;
|
|
2921
|
+
}
|
|
2525
2922
|
let teamsChannels = [];
|
|
2526
2923
|
yield this.adapter.continueConversation(this.conversationReference, (context) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2527
2924
|
const teamId = getTeamsBotInstallationId(context);
|
|
@@ -2529,7 +2926,6 @@ class TeamsBotInstallation {
|
|
|
2529
2926
|
teamsChannels = yield botbuilder.TeamsInfo.getTeamChannels(context, teamId);
|
|
2530
2927
|
}
|
|
2531
2928
|
}));
|
|
2532
|
-
const channels = [];
|
|
2533
2929
|
for (const channel of teamsChannels) {
|
|
2534
2930
|
channels.push(new Channel(this, channel));
|
|
2535
2931
|
}
|
|
@@ -2557,6 +2953,26 @@ class TeamsBotInstallation {
|
|
|
2557
2953
|
return members;
|
|
2558
2954
|
});
|
|
2559
2955
|
}
|
|
2956
|
+
/**
|
|
2957
|
+
* Get team details from this bot installation
|
|
2958
|
+
*
|
|
2959
|
+
* @returns the team details if bot is installed into a team, otherwise returns undefined.
|
|
2960
|
+
*/
|
|
2961
|
+
getTeamDetails() {
|
|
2962
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2963
|
+
if (this.type !== exports.NotificationTargetType.Channel) {
|
|
2964
|
+
return undefined;
|
|
2965
|
+
}
|
|
2966
|
+
let teamDetails;
|
|
2967
|
+
yield this.adapter.continueConversation(this.conversationReference, (context) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
2968
|
+
const teamId = getTeamsBotInstallationId(context);
|
|
2969
|
+
if (teamId !== undefined) {
|
|
2970
|
+
teamDetails = yield botbuilder.TeamsInfo.getTeamDetails(context, teamId);
|
|
2971
|
+
}
|
|
2972
|
+
}));
|
|
2973
|
+
return teamDetails;
|
|
2974
|
+
});
|
|
2975
|
+
}
|
|
2560
2976
|
}
|
|
2561
2977
|
/**
|
|
2562
2978
|
* Provide utilities to send notification to varies targets (e.g., member, group, channel).
|
|
@@ -2618,6 +3034,488 @@ class NotificationBot {
|
|
|
2618
3034
|
return targets;
|
|
2619
3035
|
});
|
|
2620
3036
|
}
|
|
3037
|
+
/**
|
|
3038
|
+
* Returns the first {@link Member} where predicate is true, and undefined otherwise.
|
|
3039
|
+
*
|
|
3040
|
+
* @param predicate find calls predicate once for each member of the installation,
|
|
3041
|
+
* until it finds one where predicate returns true. If such a member is found, find
|
|
3042
|
+
* immediately returns that member. Otherwise, find returns undefined.
|
|
3043
|
+
* @param scope the scope to find members from the installations
|
|
3044
|
+
* (personal chat, group chat, Teams channel).
|
|
3045
|
+
* @returns the first {@link Member} where predicate is true, and undefined otherwise.
|
|
3046
|
+
*/
|
|
3047
|
+
findMember(predicate, scope) {
|
|
3048
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3049
|
+
for (const target of yield this.installations()) {
|
|
3050
|
+
if (this.matchSearchScope(target, scope)) {
|
|
3051
|
+
for (const member of yield target.members()) {
|
|
3052
|
+
if (yield predicate(member)) {
|
|
3053
|
+
return member;
|
|
3054
|
+
}
|
|
3055
|
+
}
|
|
3056
|
+
}
|
|
3057
|
+
}
|
|
3058
|
+
return;
|
|
3059
|
+
});
|
|
3060
|
+
}
|
|
3061
|
+
/**
|
|
3062
|
+
* Returns the first {@link Channel} where predicate is true, and undefined otherwise.
|
|
3063
|
+
*
|
|
3064
|
+
* @param predicate find calls predicate once for each channel of the installation,
|
|
3065
|
+
* until it finds one where predicate returns true. If such a channel is found, find
|
|
3066
|
+
* immediately returns that channel. Otherwise, find returns undefined.
|
|
3067
|
+
* @returns the first {@link Channel} where predicate is true, and undefined otherwise.
|
|
3068
|
+
*/
|
|
3069
|
+
findChannel(predicate) {
|
|
3070
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3071
|
+
for (const target of yield this.installations()) {
|
|
3072
|
+
if (target.type === exports.NotificationTargetType.Channel) {
|
|
3073
|
+
const teamDetails = yield target.getTeamDetails();
|
|
3074
|
+
for (const channel of yield target.channels()) {
|
|
3075
|
+
if (yield predicate(channel, teamDetails)) {
|
|
3076
|
+
return channel;
|
|
3077
|
+
}
|
|
3078
|
+
}
|
|
3079
|
+
}
|
|
3080
|
+
}
|
|
3081
|
+
return;
|
|
3082
|
+
});
|
|
3083
|
+
}
|
|
3084
|
+
/**
|
|
3085
|
+
* Returns all {@link Member} where predicate is true, and empty array otherwise.
|
|
3086
|
+
*
|
|
3087
|
+
* @param predicate find calls predicate for each member of the installation.
|
|
3088
|
+
* @param scope the scope to find members from the installations
|
|
3089
|
+
* (personal chat, group chat, Teams channel).
|
|
3090
|
+
* @returns an array of {@link Member} where predicate is true, and empty array otherwise.
|
|
3091
|
+
*/
|
|
3092
|
+
findAllMembers(predicate, scope) {
|
|
3093
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3094
|
+
const members = [];
|
|
3095
|
+
for (const target of yield this.installations()) {
|
|
3096
|
+
if (this.matchSearchScope(target, scope)) {
|
|
3097
|
+
for (const member of yield target.members()) {
|
|
3098
|
+
if (yield predicate(member)) {
|
|
3099
|
+
members.push(member);
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
3102
|
+
}
|
|
3103
|
+
}
|
|
3104
|
+
return members;
|
|
3105
|
+
});
|
|
3106
|
+
}
|
|
3107
|
+
/**
|
|
3108
|
+
* Returns all {@link Channel} where predicate is true, and empty array otherwise.
|
|
3109
|
+
*
|
|
3110
|
+
* @param predicate find calls predicate for each channel of the installation.
|
|
3111
|
+
* @returns an array of {@link Channel} where predicate is true, and empty array otherwise.
|
|
3112
|
+
*/
|
|
3113
|
+
findAllChannels(predicate) {
|
|
3114
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3115
|
+
const channels = [];
|
|
3116
|
+
for (const target of yield this.installations()) {
|
|
3117
|
+
if (target.type === exports.NotificationTargetType.Channel) {
|
|
3118
|
+
const teamDetails = yield target.getTeamDetails();
|
|
3119
|
+
for (const channel of yield target.channels()) {
|
|
3120
|
+
if (yield predicate(channel, teamDetails)) {
|
|
3121
|
+
channels.push(channel);
|
|
3122
|
+
}
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3125
|
+
}
|
|
3126
|
+
return channels;
|
|
3127
|
+
});
|
|
3128
|
+
}
|
|
3129
|
+
matchSearchScope(target, scope) {
|
|
3130
|
+
scope = scope !== null && scope !== void 0 ? scope : exports.SearchScope.All;
|
|
3131
|
+
return ((target.type === exports.NotificationTargetType.Channel && (scope & exports.SearchScope.Channel) !== 0) ||
|
|
3132
|
+
(target.type === exports.NotificationTargetType.Group && (scope & exports.SearchScope.Group) !== 0) ||
|
|
3133
|
+
(target.type === exports.NotificationTargetType.Person && (scope & exports.SearchScope.Person) !== 0));
|
|
3134
|
+
}
|
|
3135
|
+
}
|
|
3136
|
+
/**
|
|
3137
|
+
* The search scope when calling {@link NotificationBot.findMember} and {@link NotificationBot.findAllMembers}.
|
|
3138
|
+
* The search scope is a flagged enum and it can be combined with `|`.
|
|
3139
|
+
* For example, to search from personal chat and group chat, use `SearchScope.Person | SearchScope.Group`.
|
|
3140
|
+
*/
|
|
3141
|
+
exports.SearchScope = void 0;
|
|
3142
|
+
(function (SearchScope) {
|
|
3143
|
+
/**
|
|
3144
|
+
* Search members from the installations in personal chat only.
|
|
3145
|
+
*/
|
|
3146
|
+
SearchScope[SearchScope["Person"] = 1] = "Person";
|
|
3147
|
+
/**
|
|
3148
|
+
* Search members from the installations in group chat only.
|
|
3149
|
+
*/
|
|
3150
|
+
SearchScope[SearchScope["Group"] = 2] = "Group";
|
|
3151
|
+
/**
|
|
3152
|
+
* Search members from the installations in Teams channel only.
|
|
3153
|
+
*/
|
|
3154
|
+
SearchScope[SearchScope["Channel"] = 4] = "Channel";
|
|
3155
|
+
/**
|
|
3156
|
+
* Search members from all installations including personal chat, group chat and Teams channel.
|
|
3157
|
+
*/
|
|
3158
|
+
SearchScope[SearchScope["All"] = 7] = "All";
|
|
3159
|
+
})(exports.SearchScope || (exports.SearchScope = {}));
|
|
3160
|
+
|
|
3161
|
+
// Copyright (c) Microsoft Corporation.
|
|
3162
|
+
let DIALOG_NAME = "BotSsoExecutionDialog";
|
|
3163
|
+
let TEAMS_SSO_PROMPT_ID = "TeamsFxSsoPrompt";
|
|
3164
|
+
let COMMAND_ROUTE_DIALOG = "CommandRouteDialog";
|
|
3165
|
+
/**
|
|
3166
|
+
* Sso execution dialog, use to handle sso command
|
|
3167
|
+
*/
|
|
3168
|
+
class BotSsoExecutionDialog extends botbuilderDialogs.ComponentDialog {
|
|
3169
|
+
/**
|
|
3170
|
+
* Creates a new instance of the BotSsoExecutionDialog.
|
|
3171
|
+
* @param dedupStorage Helper storage to remove duplicated messages
|
|
3172
|
+
* @param settings The list of scopes for which the token will have access
|
|
3173
|
+
* @param teamsfx {@link TeamsFx} instance for authentication
|
|
3174
|
+
*/
|
|
3175
|
+
constructor(dedupStorage, ssoPromptSettings, teamsfx, dialogName) {
|
|
3176
|
+
super(dialogName !== null && dialogName !== void 0 ? dialogName : DIALOG_NAME);
|
|
3177
|
+
this.dedupStorageKeys = [];
|
|
3178
|
+
// Map to store the commandId and triggerPatterns, key: commandId, value: triggerPatterns
|
|
3179
|
+
this.commandMapping = new Map();
|
|
3180
|
+
if (dialogName) {
|
|
3181
|
+
DIALOG_NAME = dialogName;
|
|
3182
|
+
TEAMS_SSO_PROMPT_ID = dialogName + TEAMS_SSO_PROMPT_ID;
|
|
3183
|
+
COMMAND_ROUTE_DIALOG = dialogName + COMMAND_ROUTE_DIALOG;
|
|
3184
|
+
}
|
|
3185
|
+
this.initialDialogId = COMMAND_ROUTE_DIALOG;
|
|
3186
|
+
this.dedupStorage = dedupStorage;
|
|
3187
|
+
this.dedupStorageKeys = [];
|
|
3188
|
+
const ssoDialog = new TeamsBotSsoPrompt(teamsfx, TEAMS_SSO_PROMPT_ID, ssoPromptSettings);
|
|
3189
|
+
this.addDialog(ssoDialog);
|
|
3190
|
+
const commandRouteDialog = new botbuilderDialogs.WaterfallDialog(COMMAND_ROUTE_DIALOG, [
|
|
3191
|
+
this.commandRouteStep.bind(this),
|
|
3192
|
+
]);
|
|
3193
|
+
this.addDialog(commandRouteDialog);
|
|
3194
|
+
}
|
|
3195
|
+
/**
|
|
3196
|
+
* Add TeamsFxBotSsoCommandHandler instance
|
|
3197
|
+
* @param handler {@link BotSsoExecutionDialogHandler} callback function
|
|
3198
|
+
* @param triggerPatterns The trigger pattern
|
|
3199
|
+
*/
|
|
3200
|
+
addCommand(handler, triggerPatterns) {
|
|
3201
|
+
const commandId = this.getCommandHash(triggerPatterns);
|
|
3202
|
+
const dialog = new botbuilderDialogs.WaterfallDialog(commandId, [
|
|
3203
|
+
this.ssoStep.bind(this),
|
|
3204
|
+
this.dedupStep.bind(this),
|
|
3205
|
+
(stepContext) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3206
|
+
const tokenResponse = stepContext.result.tokenResponse;
|
|
3207
|
+
const context = stepContext.context;
|
|
3208
|
+
const message = stepContext.result.message;
|
|
3209
|
+
try {
|
|
3210
|
+
if (tokenResponse) {
|
|
3211
|
+
yield handler(context, tokenResponse, message);
|
|
3212
|
+
}
|
|
3213
|
+
else {
|
|
3214
|
+
throw new Error(ErrorMessage.FailedToRetrieveSsoToken);
|
|
3215
|
+
}
|
|
3216
|
+
return yield stepContext.endDialog();
|
|
3217
|
+
}
|
|
3218
|
+
catch (error) {
|
|
3219
|
+
const errorMsg = formatString(ErrorMessage.FailedToProcessSsoHandler, error.message);
|
|
3220
|
+
internalLogger.error(errorMsg);
|
|
3221
|
+
return yield stepContext.endDialog(new ErrorWithCode(errorMsg, exports.ErrorCode.FailedToProcessSsoHandler));
|
|
3222
|
+
}
|
|
3223
|
+
}),
|
|
3224
|
+
]);
|
|
3225
|
+
this.commandMapping.set(commandId, triggerPatterns);
|
|
3226
|
+
this.addDialog(dialog);
|
|
3227
|
+
}
|
|
3228
|
+
getCommandHash(patterns) {
|
|
3229
|
+
const expressions = Array.isArray(patterns) ? patterns : [patterns];
|
|
3230
|
+
const patternStr = expressions.join();
|
|
3231
|
+
const patternStrWithoutSpecialChar = patternStr.replace(/[^a-zA-Z0-9]/g, "");
|
|
3232
|
+
const hash = crypto.createHash("sha256").update(patternStr).digest("hex").toLowerCase();
|
|
3233
|
+
return patternStrWithoutSpecialChar + hash;
|
|
3234
|
+
}
|
|
3235
|
+
/**
|
|
3236
|
+
* The run method handles the incoming activity (in the form of a DialogContext) and passes it through the dialog system.
|
|
3237
|
+
*
|
|
3238
|
+
* @param context The context object for the current turn.
|
|
3239
|
+
* @param accessor The instance of StatePropertyAccessor for dialog system.
|
|
3240
|
+
*/
|
|
3241
|
+
run(context, accessor) {
|
|
3242
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3243
|
+
const dialogSet = new botbuilderDialogs.DialogSet(accessor);
|
|
3244
|
+
dialogSet.add(this);
|
|
3245
|
+
const dialogContext = yield dialogSet.createContext(context);
|
|
3246
|
+
this.ensureMsTeamsChannel(dialogContext);
|
|
3247
|
+
const results = yield dialogContext.continueDialog();
|
|
3248
|
+
if (results && results.status === botbuilderDialogs.DialogTurnStatus.empty) {
|
|
3249
|
+
yield dialogContext.beginDialog(this.id);
|
|
3250
|
+
}
|
|
3251
|
+
else if (results &&
|
|
3252
|
+
results.status === botbuilderDialogs.DialogTurnStatus.complete &&
|
|
3253
|
+
results.result instanceof Error) {
|
|
3254
|
+
throw results.result;
|
|
3255
|
+
}
|
|
3256
|
+
});
|
|
3257
|
+
}
|
|
3258
|
+
getActivityText(activity) {
|
|
3259
|
+
let text = activity.text;
|
|
3260
|
+
const removedMentionText = botbuilder.TurnContext.removeRecipientMention(activity);
|
|
3261
|
+
if (removedMentionText) {
|
|
3262
|
+
text = removedMentionText
|
|
3263
|
+
.toLowerCase()
|
|
3264
|
+
.replace(/\n|\r\n/g, "")
|
|
3265
|
+
.trim();
|
|
3266
|
+
}
|
|
3267
|
+
return text;
|
|
3268
|
+
}
|
|
3269
|
+
commandRouteStep(stepContext) {
|
|
3270
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3271
|
+
const turnContext = stepContext.context;
|
|
3272
|
+
const text = this.getActivityText(turnContext.activity);
|
|
3273
|
+
const commandId = this.getMatchesCommandId(text);
|
|
3274
|
+
if (commandId) {
|
|
3275
|
+
return yield stepContext.beginDialog(commandId);
|
|
3276
|
+
}
|
|
3277
|
+
const errorMsg = formatString(ErrorMessage.CannotFindCommand, turnContext.activity.text);
|
|
3278
|
+
internalLogger.error(errorMsg);
|
|
3279
|
+
throw new ErrorWithCode(errorMsg, exports.ErrorCode.CannotFindCommand);
|
|
3280
|
+
});
|
|
3281
|
+
}
|
|
3282
|
+
ssoStep(stepContext) {
|
|
3283
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3284
|
+
try {
|
|
3285
|
+
const turnContext = stepContext.context;
|
|
3286
|
+
const text = this.getActivityText(turnContext.activity);
|
|
3287
|
+
const message = {
|
|
3288
|
+
text,
|
|
3289
|
+
};
|
|
3290
|
+
stepContext.options.commandMessage = message;
|
|
3291
|
+
return yield stepContext.beginDialog(TEAMS_SSO_PROMPT_ID);
|
|
3292
|
+
}
|
|
3293
|
+
catch (error) {
|
|
3294
|
+
const errorMsg = formatString(ErrorMessage.FailedToRunSsoStep, error.message);
|
|
3295
|
+
internalLogger.error(errorMsg);
|
|
3296
|
+
return yield stepContext.endDialog(new ErrorWithCode(errorMsg, exports.ErrorCode.FailedToRunSsoStep));
|
|
3297
|
+
}
|
|
3298
|
+
});
|
|
3299
|
+
}
|
|
3300
|
+
dedupStep(stepContext) {
|
|
3301
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3302
|
+
const tokenResponse = stepContext.result;
|
|
3303
|
+
if (!tokenResponse) {
|
|
3304
|
+
internalLogger.error(ErrorMessage.FailedToRetrieveSsoToken);
|
|
3305
|
+
return yield stepContext.endDialog(new ErrorWithCode(ErrorMessage.FailedToRetrieveSsoToken, exports.ErrorCode.FailedToRunSsoStep));
|
|
3306
|
+
}
|
|
3307
|
+
try {
|
|
3308
|
+
// Only dedup after ssoStep to make sure that all Teams client would receive the login request
|
|
3309
|
+
if (tokenResponse && (yield this.shouldDedup(stepContext.context))) {
|
|
3310
|
+
return botbuilderDialogs.Dialog.EndOfTurn;
|
|
3311
|
+
}
|
|
3312
|
+
return yield stepContext.next({
|
|
3313
|
+
tokenResponse,
|
|
3314
|
+
message: stepContext.options.commandMessage,
|
|
3315
|
+
});
|
|
3316
|
+
}
|
|
3317
|
+
catch (error) {
|
|
3318
|
+
const errorMsg = formatString(ErrorMessage.FailedToRunDedupStep, error.message);
|
|
3319
|
+
internalLogger.error(errorMsg);
|
|
3320
|
+
return yield stepContext.endDialog(new ErrorWithCode(errorMsg, exports.ErrorCode.FailedToRunDedupStep));
|
|
3321
|
+
}
|
|
3322
|
+
});
|
|
3323
|
+
}
|
|
3324
|
+
/**
|
|
3325
|
+
* Called when the component is ending.
|
|
3326
|
+
*
|
|
3327
|
+
* @param context Context for the current turn of conversation.
|
|
3328
|
+
*/
|
|
3329
|
+
onEndDialog(context) {
|
|
3330
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3331
|
+
const conversationId = context.activity.conversation.id;
|
|
3332
|
+
const currentDedupKeys = this.dedupStorageKeys.filter((key) => key.indexOf(conversationId) > 0);
|
|
3333
|
+
yield this.dedupStorage.delete(currentDedupKeys);
|
|
3334
|
+
this.dedupStorageKeys = this.dedupStorageKeys.filter((key) => key.indexOf(conversationId) < 0);
|
|
3335
|
+
});
|
|
3336
|
+
}
|
|
3337
|
+
/**
|
|
3338
|
+
* If a user is signed into multiple Teams clients, the Bot might receive a "signin/tokenExchange" from each client.
|
|
3339
|
+
* Each token exchange request for a specific user login will have an identical activity.value.Id.
|
|
3340
|
+
* Only one of these token exchange requests should be processed by the bot. For a distributed bot in production,
|
|
3341
|
+
* this requires a distributed storage to ensure only one token exchange is processed.
|
|
3342
|
+
* @param context Context for the current turn of conversation.
|
|
3343
|
+
* @returns boolean value indicate whether the message should be removed
|
|
3344
|
+
*/
|
|
3345
|
+
shouldDedup(context) {
|
|
3346
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3347
|
+
const storeItem = {
|
|
3348
|
+
eTag: context.activity.value.id,
|
|
3349
|
+
};
|
|
3350
|
+
const key = this.getStorageKey(context);
|
|
3351
|
+
const storeItems = { [key]: storeItem };
|
|
3352
|
+
try {
|
|
3353
|
+
yield this.dedupStorage.write(storeItems);
|
|
3354
|
+
this.dedupStorageKeys.push(key);
|
|
3355
|
+
}
|
|
3356
|
+
catch (err) {
|
|
3357
|
+
if (err instanceof Error && err.message.indexOf("eTag conflict")) {
|
|
3358
|
+
return true;
|
|
3359
|
+
}
|
|
3360
|
+
throw err;
|
|
3361
|
+
}
|
|
3362
|
+
return false;
|
|
3363
|
+
});
|
|
3364
|
+
}
|
|
3365
|
+
getStorageKey(context) {
|
|
3366
|
+
if (!context || !context.activity || !context.activity.conversation) {
|
|
3367
|
+
throw new Error("Invalid context, can not get storage key!");
|
|
3368
|
+
}
|
|
3369
|
+
const activity = context.activity;
|
|
3370
|
+
const channelId = activity.channelId;
|
|
3371
|
+
const conversationId = activity.conversation.id;
|
|
3372
|
+
if (activity.type !== botbuilder.ActivityTypes.Invoke || activity.name !== botbuilder.tokenExchangeOperationName) {
|
|
3373
|
+
throw new Error("TokenExchangeState can only be used with Invokes of signin/tokenExchange.");
|
|
3374
|
+
}
|
|
3375
|
+
const value = activity.value;
|
|
3376
|
+
if (!value || !value.id) {
|
|
3377
|
+
throw new Error("Invalid signin/tokenExchange. Missing activity.value.id.");
|
|
3378
|
+
}
|
|
3379
|
+
return `${channelId}/${conversationId}/${value.id}`;
|
|
3380
|
+
}
|
|
3381
|
+
matchPattern(pattern, text) {
|
|
3382
|
+
if (text) {
|
|
3383
|
+
if (typeof pattern === "string") {
|
|
3384
|
+
const regExp = new RegExp(pattern, "i");
|
|
3385
|
+
return regExp.test(text);
|
|
3386
|
+
}
|
|
3387
|
+
if (pattern instanceof RegExp) {
|
|
3388
|
+
const matches = text.match(pattern);
|
|
3389
|
+
return matches !== null && matches !== void 0 ? matches : false;
|
|
3390
|
+
}
|
|
3391
|
+
}
|
|
3392
|
+
return false;
|
|
3393
|
+
}
|
|
3394
|
+
isPatternMatched(patterns, text) {
|
|
3395
|
+
const expressions = Array.isArray(patterns) ? patterns : [patterns];
|
|
3396
|
+
for (const ex of expressions) {
|
|
3397
|
+
const matches = this.matchPattern(ex, text);
|
|
3398
|
+
return !!matches;
|
|
3399
|
+
}
|
|
3400
|
+
return false;
|
|
3401
|
+
}
|
|
3402
|
+
getMatchesCommandId(text) {
|
|
3403
|
+
for (const command of this.commandMapping) {
|
|
3404
|
+
const pattern = command[1];
|
|
3405
|
+
if (this.isPatternMatched(pattern, text)) {
|
|
3406
|
+
return command[0];
|
|
3407
|
+
}
|
|
3408
|
+
}
|
|
3409
|
+
return undefined;
|
|
3410
|
+
}
|
|
3411
|
+
/**
|
|
3412
|
+
* Ensure bot is running in MS Teams since TeamsBotSsoPrompt is only supported in MS Teams channel.
|
|
3413
|
+
* @param dc dialog context
|
|
3414
|
+
* @throws {@link ErrorCode|ChannelNotSupported} if bot channel is not MS Teams
|
|
3415
|
+
* @internal
|
|
3416
|
+
*/
|
|
3417
|
+
ensureMsTeamsChannel(dc) {
|
|
3418
|
+
if (dc.context.activity.channelId != botbuilder.Channels.Msteams) {
|
|
3419
|
+
const errorMsg = formatString(ErrorMessage.OnlyMSTeamsChannelSupported, "SSO execution dialog");
|
|
3420
|
+
internalLogger.error(errorMsg);
|
|
3421
|
+
throw new ErrorWithCode(errorMsg, exports.ErrorCode.ChannelNotSupported);
|
|
3422
|
+
}
|
|
3423
|
+
}
|
|
3424
|
+
}
|
|
3425
|
+
|
|
3426
|
+
// Copyright (c) Microsoft Corporation.
|
|
3427
|
+
/**
|
|
3428
|
+
* Default SSO execution activity handler
|
|
3429
|
+
*/
|
|
3430
|
+
class DefaultBotSsoExecutionActivityHandler extends botbuilder.TeamsActivityHandler {
|
|
3431
|
+
/**
|
|
3432
|
+
* Creates a new instance of the DefaultBotSsoExecutionActivityHandler.
|
|
3433
|
+
* @param ssoConfig configuration for SSO command bot
|
|
3434
|
+
*
|
|
3435
|
+
* @remarks
|
|
3436
|
+
* In the constructor, it uses BotSsoConfig parameter which from {@link ConversationBot} options to initialize {@link BotSsoExecutionDialog}.
|
|
3437
|
+
* It also need to register an event handler for the message event which trigger {@link BotSsoExecutionDialog} instance.
|
|
3438
|
+
*/
|
|
3439
|
+
constructor(ssoConfig) {
|
|
3440
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
3441
|
+
super();
|
|
3442
|
+
const memoryStorage = new botbuilder.MemoryStorage();
|
|
3443
|
+
const userState = (_b = (_a = ssoConfig.dialog) === null || _a === void 0 ? void 0 : _a.userState) !== null && _b !== void 0 ? _b : new botbuilder.UserState(memoryStorage);
|
|
3444
|
+
const conversationState = (_d = (_c = ssoConfig.dialog) === null || _c === void 0 ? void 0 : _c.conversationState) !== null && _d !== void 0 ? _d : new botbuilder.ConversationState(memoryStorage);
|
|
3445
|
+
const dedupStorage = (_f = (_e = ssoConfig.dialog) === null || _e === void 0 ? void 0 : _e.dedupStorage) !== null && _f !== void 0 ? _f : memoryStorage;
|
|
3446
|
+
const _l = ssoConfig.aad, { scopes } = _l, customConfig = tslib.__rest(_l, ["scopes"]);
|
|
3447
|
+
const settings = {
|
|
3448
|
+
scopes: scopes,
|
|
3449
|
+
timeout: (_h = (_g = ssoConfig.dialog) === null || _g === void 0 ? void 0 : _g.ssoPromptConfig) === null || _h === void 0 ? void 0 : _h.timeout,
|
|
3450
|
+
endOnInvalidMessage: (_k = (_j = ssoConfig.dialog) === null || _j === void 0 ? void 0 : _j.ssoPromptConfig) === null || _k === void 0 ? void 0 : _k.endOnInvalidMessage,
|
|
3451
|
+
};
|
|
3452
|
+
const teamsfx = new TeamsFx(exports.IdentityType.User, Object.assign({}, customConfig));
|
|
3453
|
+
this.ssoExecutionDialog = new BotSsoExecutionDialog(dedupStorage, settings, teamsfx);
|
|
3454
|
+
this.conversationState = conversationState;
|
|
3455
|
+
this.dialogState = conversationState.createProperty("DialogState");
|
|
3456
|
+
this.userState = userState;
|
|
3457
|
+
this.onMessage((context, next) => tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3458
|
+
yield this.ssoExecutionDialog.run(context, this.dialogState);
|
|
3459
|
+
yield next();
|
|
3460
|
+
}));
|
|
3461
|
+
}
|
|
3462
|
+
/**
|
|
3463
|
+
* Add TeamsFxBotSsoCommandHandler instance to SSO execution dialog
|
|
3464
|
+
* @param handler {@link BotSsoExecutionDialogHandler} callback function
|
|
3465
|
+
* @param triggerPatterns The trigger pattern
|
|
3466
|
+
*
|
|
3467
|
+
* @remarks
|
|
3468
|
+
* This function is used to add SSO command to {@link BotSsoExecutionDialog} instance.
|
|
3469
|
+
*/
|
|
3470
|
+
addCommand(handler, triggerPatterns) {
|
|
3471
|
+
this.ssoExecutionDialog.addCommand(handler, triggerPatterns);
|
|
3472
|
+
}
|
|
3473
|
+
/**
|
|
3474
|
+
* Called to initiate the event emission process.
|
|
3475
|
+
* @param context The context object for the current turn.
|
|
3476
|
+
*/
|
|
3477
|
+
run(context) {
|
|
3478
|
+
const _super = Object.create(null, {
|
|
3479
|
+
run: { get: () => super.run }
|
|
3480
|
+
});
|
|
3481
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3482
|
+
try {
|
|
3483
|
+
yield _super.run.call(this, context);
|
|
3484
|
+
}
|
|
3485
|
+
finally {
|
|
3486
|
+
yield this.conversationState.saveChanges(context, false);
|
|
3487
|
+
yield this.userState.saveChanges(context, false);
|
|
3488
|
+
}
|
|
3489
|
+
});
|
|
3490
|
+
}
|
|
3491
|
+
/**
|
|
3492
|
+
* Receives invoke activities with Activity name of 'signin/verifyState'.
|
|
3493
|
+
* @param context A context object for this turn.
|
|
3494
|
+
* @param query Signin state (part of signin action auth flow) verification invoke query.
|
|
3495
|
+
* @returns A promise that represents the work queued.
|
|
3496
|
+
*
|
|
3497
|
+
* @remarks
|
|
3498
|
+
* It should trigger {@link BotSsoExecutionDialog} instance to handle signin process
|
|
3499
|
+
*/
|
|
3500
|
+
handleTeamsSigninVerifyState(context, query) {
|
|
3501
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3502
|
+
yield this.ssoExecutionDialog.run(context, this.dialogState);
|
|
3503
|
+
});
|
|
3504
|
+
}
|
|
3505
|
+
/**
|
|
3506
|
+
* Receives invoke activities with Activity name of 'signin/tokenExchange'
|
|
3507
|
+
* @param context A context object for this turn.
|
|
3508
|
+
* @param query Signin state (part of signin action auth flow) verification invoke query
|
|
3509
|
+
* @returns A promise that represents the work queued.
|
|
3510
|
+
*
|
|
3511
|
+
* @remark
|
|
3512
|
+
* It should trigger {@link BotSsoExecutionDialog} instance to handle signin process
|
|
3513
|
+
*/
|
|
3514
|
+
handleTeamsSigninTokenExchange(context, query) {
|
|
3515
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3516
|
+
yield this.ssoExecutionDialog.run(context, this.dialogState);
|
|
3517
|
+
});
|
|
3518
|
+
}
|
|
2621
3519
|
}
|
|
2622
3520
|
|
|
2623
3521
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -2682,19 +3580,32 @@ class ConversationBot {
|
|
|
2682
3580
|
* @param options - initialize options
|
|
2683
3581
|
*/
|
|
2684
3582
|
constructor(options) {
|
|
2685
|
-
var _a, _b;
|
|
3583
|
+
var _a, _b, _c, _d;
|
|
2686
3584
|
if (options.adapter) {
|
|
2687
3585
|
this.adapter = options.adapter;
|
|
2688
3586
|
}
|
|
2689
3587
|
else {
|
|
2690
3588
|
this.adapter = this.createDefaultAdapter(options.adapterConfig);
|
|
2691
3589
|
}
|
|
2692
|
-
|
|
2693
|
-
|
|
3590
|
+
let ssoCommandActivityHandler;
|
|
3591
|
+
if (options === null || options === void 0 ? void 0 : options.ssoConfig) {
|
|
3592
|
+
if ((_a = options.ssoConfig.dialog) === null || _a === void 0 ? void 0 : _a.CustomBotSsoExecutionActivityHandler) {
|
|
3593
|
+
ssoCommandActivityHandler =
|
|
3594
|
+
new options.ssoConfig.dialog.CustomBotSsoExecutionActivityHandler(options.ssoConfig);
|
|
3595
|
+
}
|
|
3596
|
+
else {
|
|
3597
|
+
ssoCommandActivityHandler = new DefaultBotSsoExecutionActivityHandler(options.ssoConfig);
|
|
3598
|
+
}
|
|
2694
3599
|
}
|
|
2695
|
-
if ((_b = options.
|
|
3600
|
+
if ((_b = options.command) === null || _b === void 0 ? void 0 : _b.enabled) {
|
|
3601
|
+
this.command = new CommandBot(this.adapter, options.command, ssoCommandActivityHandler, options.ssoConfig);
|
|
3602
|
+
}
|
|
3603
|
+
if ((_c = options.notification) === null || _c === void 0 ? void 0 : _c.enabled) {
|
|
2696
3604
|
this.notification = new NotificationBot(this.adapter, options.notification);
|
|
2697
3605
|
}
|
|
3606
|
+
if ((_d = options.cardAction) === null || _d === void 0 ? void 0 : _d.enabled) {
|
|
3607
|
+
this.cardAction = new CardActionBot(this.adapter, options.cardAction);
|
|
3608
|
+
}
|
|
2698
3609
|
}
|
|
2699
3610
|
createDefaultAdapter(adapterConfig) {
|
|
2700
3611
|
const adapter = adapterConfig === undefined
|
|
@@ -2883,15 +3794,122 @@ class MessageBuilder {
|
|
|
2883
3794
|
}
|
|
2884
3795
|
}
|
|
2885
3796
|
|
|
3797
|
+
// Copyright (c) Microsoft Corporation.
|
|
3798
|
+
/**
|
|
3799
|
+
* Retrieve the OAuth Sign in Link to use in the MessagingExtensionResult Suggested Actions.
|
|
3800
|
+
* This method only work on MessageExtension with Query now.
|
|
3801
|
+
*
|
|
3802
|
+
* @param {TeamsFx} teamsfx - Used to provide configuration and auth.
|
|
3803
|
+
* @param {string | string[]} scopes - The list of scopes for which the token will have access.
|
|
3804
|
+
*
|
|
3805
|
+
* @returns SignIn link CardAction with 200 status code.
|
|
3806
|
+
*/
|
|
3807
|
+
function getSignInResponseForMessageExtension(teamsfx, scopes) {
|
|
3808
|
+
const scopesArray = getScopesArray(scopes);
|
|
3809
|
+
const signInLink = `${teamsfx.getConfig("initiateLoginEndpoint")}?scope=${encodeURI(scopesArray.join(" "))}&clientId=${teamsfx.getConfig("clientId")}&tenantId=${teamsfx.getConfig("tenantId")}`;
|
|
3810
|
+
return {
|
|
3811
|
+
composeExtension: {
|
|
3812
|
+
type: "silentAuth",
|
|
3813
|
+
suggestedActions: {
|
|
3814
|
+
actions: [
|
|
3815
|
+
{
|
|
3816
|
+
type: "openUrl",
|
|
3817
|
+
value: signInLink,
|
|
3818
|
+
title: "Message Extension OAuth",
|
|
3819
|
+
},
|
|
3820
|
+
],
|
|
3821
|
+
},
|
|
3822
|
+
},
|
|
3823
|
+
};
|
|
3824
|
+
}
|
|
3825
|
+
/**
|
|
3826
|
+
* execution in message extension with SSO token.
|
|
3827
|
+
*
|
|
3828
|
+
* @param {TurnContext} context - The context object for the current turn.
|
|
3829
|
+
* @param {AuthenticationConfiguration} config - User custom the message extension authentication configuration.
|
|
3830
|
+
* @param {string[]} scopes - The list of scopes for which the token will have access.
|
|
3831
|
+
* @param {function} logic - Business logic when executing the query in message extension with SSO or access token.
|
|
3832
|
+
*
|
|
3833
|
+
* @throws {@link ErrorCode|InternalError} when failed to get access token with unknown error.
|
|
3834
|
+
* @throws {@link ErrorCode|TokenExpiredError} when SSO token has already expired.
|
|
3835
|
+
* @throws {@link ErrorCode|ServiceError} when failed to get access token from simple auth server.
|
|
3836
|
+
* @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
|
|
3837
|
+
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
|
|
3838
|
+
*
|
|
3839
|
+
* @returns A MessageExtension Response for the activity. If the logic not return any, return void instead.
|
|
3840
|
+
*/
|
|
3841
|
+
function executionWithToken(context, config, scopes, logic) {
|
|
3842
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3843
|
+
const valueObj = context.activity.value;
|
|
3844
|
+
if (!valueObj.authentication || !valueObj.authentication.token) {
|
|
3845
|
+
internalLogger.verbose("No AccessToken in request, return silentAuth for AccessToken");
|
|
3846
|
+
return getSignInResponseForMessageExtension(new TeamsFx(exports.IdentityType.User, config), scopes);
|
|
3847
|
+
}
|
|
3848
|
+
try {
|
|
3849
|
+
const teamsfx = new TeamsFx(exports.IdentityType.User, config).setSsoToken(valueObj.authentication.token);
|
|
3850
|
+
const token = yield teamsfx.getCredential().getToken(scopes);
|
|
3851
|
+
const ssoTokenExpiration = parseJwt(valueObj.authentication.token).exp;
|
|
3852
|
+
const tokenRes = {
|
|
3853
|
+
ssoToken: valueObj.authentication.token,
|
|
3854
|
+
ssoTokenExpiration: new Date(ssoTokenExpiration * 1000).toISOString(),
|
|
3855
|
+
token: token.token,
|
|
3856
|
+
expiration: token.expiresOnTimestamp.toString(),
|
|
3857
|
+
connectionName: "",
|
|
3858
|
+
};
|
|
3859
|
+
if (logic) {
|
|
3860
|
+
return yield logic(tokenRes);
|
|
3861
|
+
}
|
|
3862
|
+
}
|
|
3863
|
+
catch (err) {
|
|
3864
|
+
if (err instanceof ErrorWithCode && err.code === exports.ErrorCode.UiRequiredError) {
|
|
3865
|
+
internalLogger.verbose("User not consent yet, return 412 to user consent first.");
|
|
3866
|
+
const response = { status: 412 };
|
|
3867
|
+
yield context.sendActivity({ value: response, type: botbuilder.ActivityTypes.InvokeResponse });
|
|
3868
|
+
return;
|
|
3869
|
+
}
|
|
3870
|
+
throw err;
|
|
3871
|
+
}
|
|
3872
|
+
});
|
|
3873
|
+
}
|
|
3874
|
+
/**
|
|
3875
|
+
* Users execute query in message extension with SSO or access token.
|
|
3876
|
+
*
|
|
3877
|
+
* @param {TurnContext} context - The context object for the current turn.
|
|
3878
|
+
* @param {AuthenticationConfiguration} config - User custom the message extension authentication configuration.
|
|
3879
|
+
* @param {string| string[]} scopes - The list of scopes for which the token will have access.
|
|
3880
|
+
* @param {function} logic - Business logic when executing the query in message extension with SSO or access token.
|
|
3881
|
+
*
|
|
3882
|
+
* @throws {@link ErrorCode|InternalError} when User invoke not response to message extension query.
|
|
3883
|
+
* @throws {@link ErrorCode|InternalError} when failed to get access token with unknown error.
|
|
3884
|
+
* @throws {@link ErrorCode|TokenExpiredError} when SSO token has already expired.
|
|
3885
|
+
* @throws {@link ErrorCode|ServiceError} when failed to get access token from simple auth server.
|
|
3886
|
+
* @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
|
|
3887
|
+
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
|
|
3888
|
+
*
|
|
3889
|
+
* @returns A MessageExtension Response for the activity. If the logic not return any, return void instead.
|
|
3890
|
+
*/
|
|
3891
|
+
function handleMessageExtensionQueryWithToken(context, config, scopes, logic) {
|
|
3892
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
3893
|
+
if (context.activity.name != "composeExtension/query") {
|
|
3894
|
+
internalLogger.error(ErrorMessage.OnlySupportInQueryActivity);
|
|
3895
|
+
throw new ErrorWithCode(formatString(ErrorMessage.OnlySupportInQueryActivity), exports.ErrorCode.FailedOperation);
|
|
3896
|
+
}
|
|
3897
|
+
return yield executionWithToken(context, config !== null && config !== void 0 ? config : {}, scopes, logic);
|
|
3898
|
+
});
|
|
3899
|
+
}
|
|
3900
|
+
|
|
2886
3901
|
exports.ApiKeyProvider = ApiKeyProvider;
|
|
2887
3902
|
exports.AppCredential = AppCredential;
|
|
2888
3903
|
exports.BasicAuthProvider = BasicAuthProvider;
|
|
2889
3904
|
exports.BearerTokenAuthProvider = BearerTokenAuthProvider;
|
|
3905
|
+
exports.BotSsoExecutionDialog = BotSsoExecutionDialog;
|
|
3906
|
+
exports.CardActionBot = CardActionBot;
|
|
2890
3907
|
exports.CertificateAuthProvider = CertificateAuthProvider;
|
|
2891
3908
|
exports.Channel = Channel;
|
|
2892
3909
|
exports.CommandBot = CommandBot;
|
|
2893
3910
|
exports.ConversationBot = ConversationBot;
|
|
2894
3911
|
exports.ErrorWithCode = ErrorWithCode;
|
|
3912
|
+
exports.InvokeResponseFactory = InvokeResponseFactory;
|
|
2895
3913
|
exports.Member = Member;
|
|
2896
3914
|
exports.MessageBuilder = MessageBuilder;
|
|
2897
3915
|
exports.MsGraphAuthProvider = MsGraphAuthProvider;
|
|
@@ -2907,6 +3925,7 @@ exports.createPemCertOption = createPemCertOption;
|
|
|
2907
3925
|
exports.createPfxCertOption = createPfxCertOption;
|
|
2908
3926
|
exports.getLogLevel = getLogLevel;
|
|
2909
3927
|
exports.getTediousConnectionConfig = getTediousConnectionConfig;
|
|
3928
|
+
exports.handleMessageExtensionQueryWithToken = handleMessageExtensionQueryWithToken;
|
|
2910
3929
|
exports.sendAdaptiveCard = sendAdaptiveCard;
|
|
2911
3930
|
exports.sendMessage = sendMessage;
|
|
2912
3931
|
exports.setLogFunction = setLogFunction;
|