@oneuptime/common 12.0.12 → 12.0.13
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/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.ts +32 -5
- package/Models/DatabaseModels/NetworkDevice.ts +64 -0
- package/Models/DatabaseModels/StatusPage.ts +59 -0
- package/Models/DatabaseModels/StatusPageOidc.ts +2 -0
- package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +19 -2
- package/Server/API/AIChatAPI.ts +55 -56
- package/Server/API/CommonAPI.ts +89 -0
- package/Server/API/MicrosoftTeamsAPI.ts +20 -9
- package/Server/API/SlackAPI.ts +13 -10
- package/Server/API/StatusPageAPI.ts +2197 -2128
- package/Server/API/TelemetryAPI.ts +72 -3
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.ts +30 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.ts +47 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
- package/Server/Middleware/UserAuthorization.ts +11 -2
- package/Server/Services/ApiKeyPermissionService.ts +116 -2
- package/Server/Services/DatabaseService.ts +17 -6
- package/Server/Services/LogAggregationService.ts +34 -0
- package/Server/Services/LogService.ts +21 -0
- package/Server/Services/NetworkSiteService.ts +12 -0
- package/Server/Services/SpanService.ts +21 -0
- package/Server/Services/TraceAggregationService.ts +15 -0
- package/Server/Services/WorkspaceNotificationRuleService.ts +172 -220
- package/Server/Types/AnalyticsDatabase/ModelPermission.ts +9 -0
- package/Server/Types/Database/Permissions/AccessControlPermission.ts +47 -16
- package/Server/Utils/APIKey/AccessPermission.ts +16 -40
- package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +144 -0
- package/Server/Utils/LogRedaction.ts +576 -0
- package/Server/Utils/Logger.ts +123 -46
- package/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.ts +94 -23
- package/Server/Utils/Monitor/MonitorResource.ts +29 -9
- package/Server/Utils/Monitor/NetworkInventoryUtil.ts +28 -7
- package/Server/Utils/SessionReplay/SessionReplayGateCacheStore.ts +56 -10
- package/Server/Utils/StartServer.ts +30 -9
- package/Server/Utils/StatusPageSearchEngineIndexing.ts +33 -0
- package/Server/Utils/Telemetry/ResourceEntityFilter.ts +441 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +488 -46
- package/Tests/App/Dashboard/MonitorTypePicker.test.tsx +300 -0
- package/Tests/App/StatusPage/StatusPageIndexPageRobotsMeta.test.ts +130 -0
- package/Tests/Models/DatabaseModels/DatabaseBaseModelToJSONObjectCache.test.ts +180 -0
- package/Tests/Models/StatusPageEnableSearchEngineIndexing.test.ts +157 -0
- package/Tests/Server/API/AIChatCancelAndFeedback.test.ts +23 -1
- package/Tests/Server/API/AIChatRouteAuthorization.test.ts +785 -0
- package/Tests/Server/API/BaseAPIApiKeyAuth.test.ts +21 -8
- package/Tests/Server/API/CommonAPIAuthGuard.test.ts +290 -0
- package/Tests/Server/API/MicrosoftTeamsManifest.test.ts +7 -1
- package/Tests/Server/API/StatusPageOverviewCache.test.ts +474 -0
- package/Tests/Server/API/StatusPageSeoSearchEngineIndexing.test.ts +189 -0
- package/Tests/Server/Infrastructure/InMemoryTTLCache.test.ts +158 -0
- package/Tests/Server/Infrastructure/Postgres/DeviceRoleAndDeclaredLinkParentMigration.test.ts +9 -60
- package/Tests/Server/Middleware/ProjectAuthorizationApiKeyMiddleware.test.ts +24 -15
- package/Tests/Server/Middleware/UserAuthorization.test.ts +79 -0
- package/Tests/Server/Services/AddNetworkDeviceReachabilityColumnsMigration.test.ts +332 -0
- package/Tests/Server/Services/ApiKeyPermissionService.test.ts +347 -0
- package/Tests/Server/Services/DatabaseServiceUpdateDebugLogging.test.ts +282 -0
- package/Tests/Server/Services/NetworkSiteService.test.ts +56 -2
- package/Tests/Server/Services/TelemetryResourceFacetFilters.test.ts +267 -0
- package/Tests/Server/Services/WorkspaceNotificationRuleTestRuleChannels.test.ts +702 -0
- package/Tests/Server/Types/Database/Permissions/AccessControlPermission.test.ts +165 -0
- package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +48 -36
- package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +213 -0
- package/Tests/Server/Utils/LogRedaction.test.ts +415 -0
- package/Tests/Server/Utils/LoggerCredentialLeak.test.ts +245 -0
- package/Tests/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.test.ts +374 -4
- package/Tests/Server/Utils/Monitor/MonitorResourceIngestedStepSelection.test.ts +455 -0
- package/Tests/Server/Utils/Monitor/NetworkDeviceReachabilityRoundTrip.test.ts +369 -0
- package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +86 -8
- package/Tests/Server/Utils/PrivacyFilterUtil.test.ts +64 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayGateCacheStore.test.ts +207 -0
- package/Tests/Server/Utils/StartServerBodyVerify.test.ts +335 -0
- package/Tests/Server/Utils/StatusPageSearchEngineIndexing.test.ts +60 -0
- package/Tests/Server/Utils/Telemetry/ResourceEntityFilter.test.ts +435 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelSend.test.ts +607 -62
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsInstalledTeamIdSpace.test.ts +778 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsTeamInstalls.test.ts +44 -10
- package/Tests/Types/API/HostnameFromAuthority.test.ts +164 -0
- package/Tests/Types/Database/AccessControl/ColumnAccessControlCache.test.ts +344 -0
- package/Tests/Types/Database/DatabasePropertyFindOperator.test.ts +518 -0
- package/Tests/Types/Database/TableColumnMetadataCache.test.ts +286 -0
- package/Tests/Types/Monitor/MonitorStep.test.ts +100 -0
- package/Tests/Types/Monitor/MonitorTypeKeywords.test.ts +360 -0
- package/Tests/Types/StatusPage/SearchEngineIndexing.test.ts +86 -0
- package/Tests/Types/Telemetry/ResourceEntityFacet.test.ts +254 -0
- package/Tests/UI/Components/CardSelect.test.tsx +1021 -0
- package/Tests/UI/Components/MasterPage.test.tsx +36 -1
- package/Tests/Utils/Monitor/MonitorMetricType.test.ts +66 -1
- package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +115 -6
- package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +610 -0
- package/Tests/Utils/NetworkSite/SiteStatusRollupUtil.test.ts +114 -45
- package/Types/API/Hostname.ts +79 -0
- package/Types/Database/AccessControl/ColumnAccessControl.ts +33 -11
- package/Types/Database/AccessControl/ColumnBillingAccessControl.ts +33 -11
- package/Types/Database/DatabaseProperty.ts +38 -0
- package/Types/Database/TableColumn.ts +34 -7
- package/Types/Events/Recurring.ts +16 -1
- package/Types/Monitor/MonitorStep.ts +13 -1
- package/Types/Monitor/MonitorType.ts +345 -40
- package/Types/Monitor/SSLMonitor/SslMonitorResponse.ts +43 -0
- package/Types/StatusPage/SearchEngineIndexing.ts +61 -0
- package/Types/Telemetry/ResourceEntityFacet.ts +211 -0
- package/UI/Components/CardSelect/CardSelect.tsx +714 -105
- package/UI/Components/EmptyState/EmptyState.tsx +8 -1
- package/UI/Components/Footer/Footer.tsx +32 -6
- package/UI/Components/Forms/Fields/FormField.tsx +3 -0
- package/UI/Components/Forms/Types/Field.ts +8 -0
- package/UI/Components/Loader/PageLoader.tsx +29 -8
- package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +26 -4
- package/UI/Components/Markdown.tsx/LazyMarkdownViewer.tsx +17 -1
- package/UI/Components/MasterPage/MasterPage.tsx +24 -11
- package/Utils/Monitor/MonitorMetricType.ts +16 -1
- package/Utils/Monitor/NetworkTopologyUtil.ts +60 -8
- package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +262 -0
- package/Utils/NetworkSite/SiteStatusRollupUtil.ts +41 -24
- package/Utils/Telemetry/CrossSignalScope.ts +75 -4
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js +20 -4
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +66 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPage.js +60 -0
- package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageOidc.js +2 -0
- package/build/dist/Models/DatabaseModels/StatusPageOidc.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
- package/build/dist/Server/API/AIChatAPI.js +48 -35
- package/build/dist/Server/API/AIChatAPI.js.map +1 -1
- package/build/dist/Server/API/CommonAPI.js +59 -0
- package/build/dist/Server/API/CommonAPI.js.map +1 -1
- package/build/dist/Server/API/MicrosoftTeamsAPI.js +20 -6
- package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
- package/build/dist/Server/API/SlackAPI.js +13 -10
- package/build/dist/Server/API/SlackAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +745 -673
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/TelemetryAPI.js +34 -3
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.js +23 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.js +34 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/UserAuthorization.js +6 -2
- package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
- package/build/dist/Server/Services/ApiKeyPermissionService.js +90 -1
- package/build/dist/Server/Services/ApiKeyPermissionService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +15 -6
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/LogAggregationService.js +2 -0
- package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
- package/build/dist/Server/Services/LogService.js +16 -0
- package/build/dist/Server/Services/LogService.js.map +1 -1
- package/build/dist/Server/Services/NetworkSiteService.js +12 -0
- package/build/dist/Server/Services/NetworkSiteService.js.map +1 -1
- package/build/dist/Server/Services/SpanService.js +16 -0
- package/build/dist/Server/Services/SpanService.js.map +1 -1
- package/build/dist/Server/Services/TraceAggregationService.js +2 -0
- package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +137 -164
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js +9 -0
- package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/AccessControlPermission.js +21 -13
- package/build/dist/Server/Types/Database/Permissions/AccessControlPermission.js.map +1 -1
- package/build/dist/Server/Utils/APIKey/AccessPermission.js +9 -32
- package/build/dist/Server/Utils/APIKey/AccessPermission.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +87 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
- package/build/dist/Server/Utils/LogRedaction.js +449 -0
- package/build/dist/Server/Utils/LogRedaction.js.map +1 -0
- package/build/dist/Server/Utils/Logger.js +98 -45
- package/build/dist/Server/Utils/Logger.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js +65 -13
- package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +20 -3
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +27 -7
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
- package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCacheStore.js +29 -10
- package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCacheStore.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +10 -7
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/StatusPageSearchEngineIndexing.js +24 -0
- package/build/dist/Server/Utils/StatusPageSearchEngineIndexing.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +311 -0
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +366 -37
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Types/API/Hostname.js +63 -0
- package/build/dist/Types/API/Hostname.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js +20 -6
- package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js +20 -6
- package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js.map +1 -1
- package/build/dist/Types/Database/DatabaseProperty.js +38 -0
- package/build/dist/Types/Database/DatabaseProperty.js.map +1 -1
- package/build/dist/Types/Database/TableColumn.js +24 -6
- package/build/dist/Types/Database/TableColumn.js.map +1 -1
- package/build/dist/Types/Events/Recurring.js +13 -1
- package/build/dist/Types/Events/Recurring.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +9 -1
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorType.js +330 -31
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Types/StatusPage/SearchEngineIndexing.js +55 -0
- package/build/dist/Types/StatusPage/SearchEngineIndexing.js.map +1 -0
- package/build/dist/Types/Telemetry/ResourceEntityFacet.js +156 -0
- package/build/dist/Types/Telemetry/ResourceEntityFacet.js.map +1 -0
- package/build/dist/UI/Components/CardSelect/CardSelect.js +360 -40
- package/build/dist/UI/Components/CardSelect/CardSelect.js.map +1 -1
- package/build/dist/UI/Components/EmptyState/EmptyState.js +1 -1
- package/build/dist/UI/Components/EmptyState/EmptyState.js.map +1 -1
- package/build/dist/UI/Components/Footer/Footer.js +7 -4
- package/build/dist/UI/Components/Footer/Footer.js.map +1 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js +1 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
- package/build/dist/UI/Components/Loader/PageLoader.js +15 -5
- package/build/dist/UI/Components/Loader/PageLoader.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +16 -3
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/LazyMarkdownViewer.js +13 -1
- package/build/dist/UI/Components/Markdown.tsx/LazyMarkdownViewer.js.map +1 -1
- package/build/dist/UI/Components/MasterPage/MasterPage.js +10 -2
- package/build/dist/UI/Components/MasterPage/MasterPage.js.map +1 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js +13 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +34 -7
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +177 -0
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -0
- package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js +23 -27
- package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js.map +1 -1
- package/build/dist/Utils/Telemetry/CrossSignalScope.js +44 -4
- package/build/dist/Utils/Telemetry/CrossSignalScope.js.map +1 -1
- package/package.json +1 -1
|
@@ -44,6 +44,20 @@ import MicrosoftTeamsOnCallDutyActions from "./Actions/OnCallDutyPolicy";
|
|
|
44
44
|
import AccessTokenService from "../../../Services/AccessTokenService";
|
|
45
45
|
// Microsoft Teams apps should always be single-tenant
|
|
46
46
|
const MICROSOFT_TEAMS_APP_TYPE = "SingleTenant";
|
|
47
|
+
/*
|
|
48
|
+
* Whether the OneUptime Teams app is installed in a given team.
|
|
49
|
+
*
|
|
50
|
+
* Unknown is a first-class outcome, not an error: checking installation needs a
|
|
51
|
+
* Graph permission that deployments connected before it was documented have not
|
|
52
|
+
* consented to, and a tenant that answers "I won't tell you" must never be
|
|
53
|
+
* reported to an admin as "the app is not installed".
|
|
54
|
+
*/
|
|
55
|
+
export var MicrosoftTeamsAppInstallState;
|
|
56
|
+
(function (MicrosoftTeamsAppInstallState) {
|
|
57
|
+
MicrosoftTeamsAppInstallState["Installed"] = "Installed";
|
|
58
|
+
MicrosoftTeamsAppInstallState["NotInstalled"] = "NotInstalled";
|
|
59
|
+
MicrosoftTeamsAppInstallState["Unknown"] = "Unknown";
|
|
60
|
+
})(MicrosoftTeamsAppInstallState || (MicrosoftTeamsAppInstallState = {}));
|
|
47
61
|
/*
|
|
48
62
|
* Microsoft's wording when the Bot Framework refuses a proactive post because
|
|
49
63
|
* the app is not a member of the target conversation. Matched case-insensitively
|
|
@@ -959,6 +973,12 @@ class MicrosoftTeamsUtil extends WorkspaceBase {
|
|
|
959
973
|
});
|
|
960
974
|
logger.debug(`Team ID: ${data.teamId}`);
|
|
961
975
|
logger.debug(`Adaptive card: ${JSON.stringify(data.adaptiveCard)}`);
|
|
976
|
+
/*
|
|
977
|
+
* Declared out here so the catch block can tell a rejection we predicted
|
|
978
|
+
* from one we could not, and word the error accordingly.
|
|
979
|
+
*/
|
|
980
|
+
let installState = MicrosoftTeamsAppInstallState.Unknown;
|
|
981
|
+
let installStateCameFromGraph = false;
|
|
962
982
|
try {
|
|
963
983
|
// Get project auth to retrieve bot ID
|
|
964
984
|
const projectAuth = await WorkspaceProjectAuthTokenService.getProjectAuth({
|
|
@@ -989,25 +1009,36 @@ class MicrosoftTeamsUtil extends WorkspaceBase {
|
|
|
989
1009
|
throw new BadDataException(`"${data.workspaceChannel.name}" is a shared channel, and Microsoft Teams does not allow bots to post in shared channels. Please pick a standard or private channel instead.`);
|
|
990
1010
|
}
|
|
991
1011
|
/*
|
|
992
|
-
* Preflight
|
|
993
|
-
*
|
|
994
|
-
*
|
|
995
|
-
* regardless of installation — so reaching this point proves nothing
|
|
996
|
-
* about whether we can actually post.
|
|
1012
|
+
* Preflight. Channels are discovered with tenant-wide Graph application
|
|
1013
|
+
* permissions, which see every team regardless of installation — so
|
|
1014
|
+
* reaching this point proves nothing about whether we can actually post.
|
|
997
1015
|
*
|
|
998
|
-
*
|
|
999
|
-
*
|
|
1000
|
-
*
|
|
1001
|
-
*
|
|
1002
|
-
*
|
|
1016
|
+
* An install we recorded from a bot activity is the cheap positive
|
|
1017
|
+
* signal, and it also carries the serviceUrl this send needs. When we
|
|
1018
|
+
* have no record we ask Graph rather than assuming: absence from
|
|
1019
|
+
* installedTeams used to be reported to admins as "the app is not
|
|
1020
|
+
* installed", which is a claim install events alone cannot support (they
|
|
1021
|
+
* only arrive for installs that happened while OneUptime was reachable).
|
|
1022
|
+
* Only a verified negative refuses the send; anything we cannot verify
|
|
1023
|
+
* goes to Microsoft, which is the real authority.
|
|
1003
1024
|
*/
|
|
1004
|
-
const
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1025
|
+
const installedTeam = this.indexInstalledTeamsByGraphTeamId(miscData.installedTeams)[data.teamId];
|
|
1026
|
+
if (installedTeam) {
|
|
1027
|
+
installState = MicrosoftTeamsAppInstallState.Installed;
|
|
1028
|
+
}
|
|
1029
|
+
else {
|
|
1030
|
+
installState = await this.isAppInstalledInTeam({
|
|
1031
|
+
authToken: data.authToken,
|
|
1032
|
+
projectId: data.projectId,
|
|
1033
|
+
teamId: data.teamId,
|
|
1034
|
+
});
|
|
1035
|
+
installStateCameFromGraph = true;
|
|
1036
|
+
if (installState === MicrosoftTeamsAppInstallState.NotInstalled) {
|
|
1037
|
+
throw new BadDataException(this.getBotNotInTeamMessage({
|
|
1038
|
+
channelName: data.workspaceChannel.name,
|
|
1039
|
+
membershipType: data.workspaceChannel.membershipType,
|
|
1040
|
+
}));
|
|
1041
|
+
}
|
|
1011
1042
|
}
|
|
1012
1043
|
// Get Bot Framework adapter
|
|
1013
1044
|
const adapter = this.getBotAdapter();
|
|
@@ -1062,13 +1093,39 @@ class MicrosoftTeamsUtil extends WorkspaceBase {
|
|
|
1062
1093
|
logger.error(error);
|
|
1063
1094
|
/*
|
|
1064
1095
|
* Microsoft's roster rejection is meaningless to an admin ("The bot is
|
|
1065
|
-
* not part of the conversation roster"). Replace it with
|
|
1066
|
-
*
|
|
1096
|
+
* not part of the conversation roster"). Replace it with something
|
|
1097
|
+
* actionable — but only claim the app is missing from the team when we
|
|
1098
|
+
* checked and it is. Otherwise the app can be installed exactly as
|
|
1099
|
+
* documented and still be told to install it, which is how this error
|
|
1100
|
+
* sent admins in circles.
|
|
1067
1101
|
*/
|
|
1068
1102
|
if (this.isBotNotInConversationRosterError(error)) {
|
|
1069
|
-
|
|
1103
|
+
/*
|
|
1104
|
+
* A local install record got us past the preflight without asking
|
|
1105
|
+
* Graph, and it can be stale — the app may have been removed from the
|
|
1106
|
+
* team since, and an uninstall event only reaches us if OneUptime was
|
|
1107
|
+
* reachable at the time. So confirm before wording the error. This is
|
|
1108
|
+
* the failure path, so the extra call costs nothing in normal operation.
|
|
1109
|
+
*/
|
|
1110
|
+
let verifiedInstallState = installState;
|
|
1111
|
+
if (!installStateCameFromGraph) {
|
|
1112
|
+
verifiedInstallState = await this.isAppInstalledInTeam({
|
|
1113
|
+
authToken: data.authToken,
|
|
1114
|
+
projectId: data.projectId,
|
|
1115
|
+
teamId: data.teamId,
|
|
1116
|
+
});
|
|
1117
|
+
}
|
|
1118
|
+
if (verifiedInstallState === MicrosoftTeamsAppInstallState.NotInstalled) {
|
|
1119
|
+
throw new BadDataException(this.getBotNotInTeamMessage({
|
|
1120
|
+
channelName: data.workspaceChannel.name,
|
|
1121
|
+
membershipType: data.workspaceChannel.membershipType,
|
|
1122
|
+
}));
|
|
1123
|
+
}
|
|
1124
|
+
throw new BadDataException(this.getRosterRejectionMessage({
|
|
1070
1125
|
channelName: data.workspaceChannel.name,
|
|
1071
1126
|
membershipType: data.workspaceChannel.membershipType,
|
|
1127
|
+
installState: verifiedInstallState,
|
|
1128
|
+
microsoftError: error,
|
|
1072
1129
|
}));
|
|
1073
1130
|
}
|
|
1074
1131
|
throw error;
|
|
@@ -1098,6 +1155,94 @@ class MicrosoftTeamsUtil extends WorkspaceBase {
|
|
|
1098
1155
|
}
|
|
1099
1156
|
return `The OneUptime app is not installed in the Microsoft Teams team that owns "${data.channelName}". In Microsoft Teams, click the "..." next to the team name, then Manage team > Apps > More apps, and add OneUptime. Installing OneUptime for yourself or in a chat is not the same as adding it to the team.`;
|
|
1100
1157
|
}
|
|
1158
|
+
/*
|
|
1159
|
+
* Microsoft rejected the post and we could not confirm why. Everything here
|
|
1160
|
+
* is a real cause of that rejection for an app that IS present in the team's
|
|
1161
|
+
* app list, which is the case getBotNotInTeamMessage got wrong: the app tile
|
|
1162
|
+
* showing up in Manage team > Apps does not mean the bot behind it is the one
|
|
1163
|
+
* this deployment authenticates as. Microsoft's own wording is included so
|
|
1164
|
+
* the raw error is not lost in the rewrite.
|
|
1165
|
+
*/
|
|
1166
|
+
static getRosterRejectionMessage(data) {
|
|
1167
|
+
const causes = [];
|
|
1168
|
+
if (data.membershipType === "private") {
|
|
1169
|
+
causes.push(`"${data.channelName}" is a private channel, which needs the app installed into the channel itself (channel "..." > Manage channel > Apps > Add an app) — a team-level install does not cover it`);
|
|
1170
|
+
}
|
|
1171
|
+
else if (data.installState === MicrosoftTeamsAppInstallState.Installed) {
|
|
1172
|
+
causes.push("the app is installed in this team, so the bot behind it may not be the one this OneUptime deployment uses — check that the Teams app package was built from this deployment (Project Settings > Workspace > Microsoft Teams) and that its bot id matches MICROSOFT_TEAMS_APP_CLIENT_ID");
|
|
1173
|
+
}
|
|
1174
|
+
else {
|
|
1175
|
+
causes.push('the OneUptime app has not been added to this team (team "..." > Manage team > Apps > More apps), or the app that was added is a different package whose bot id is not this deployment\'s MICROSOFT_TEAMS_APP_CLIENT_ID');
|
|
1176
|
+
}
|
|
1177
|
+
causes.push("the Azure Bot resource for this deployment does not have the Microsoft Teams channel enabled");
|
|
1178
|
+
const microsoftMessage = data.microsoftError instanceof Error
|
|
1179
|
+
? data.microsoftError.message
|
|
1180
|
+
: String(data.microsoftError || "");
|
|
1181
|
+
const suffix = microsoftMessage
|
|
1182
|
+
? ` Microsoft's response was: "${microsoftMessage}"`
|
|
1183
|
+
: "";
|
|
1184
|
+
return `Microsoft Teams refused the message to "${data.channelName}" because the OneUptime bot is not a member of that conversation. Likely causes: ${causes.join("; ")}.${suffix}`;
|
|
1185
|
+
}
|
|
1186
|
+
/*
|
|
1187
|
+
* Asks Graph whether this deployment's Teams app is installed in a team.
|
|
1188
|
+
*
|
|
1189
|
+
* Matching is on teamsApp.externalId, which is the manifest id — and the
|
|
1190
|
+
* manifest OneUptime generates sets both that and the bot id to
|
|
1191
|
+
* MICROSOFT_TEAMS_APP_CLIENT_ID. So this answers the question that actually
|
|
1192
|
+
* matters ("is the app THIS deployment authenticates as installed here?"),
|
|
1193
|
+
* not the weaker one an admin can answer by eye ("is something called
|
|
1194
|
+
* OneUptime in the app list?").
|
|
1195
|
+
*
|
|
1196
|
+
* Every failure is Unknown. The call needs TeamsAppInstallation.ReadForTeam.All,
|
|
1197
|
+
* which deployments connected before it was documented have not granted, and a
|
|
1198
|
+
* missing permission must not be reported as a missing install.
|
|
1199
|
+
*/
|
|
1200
|
+
static async isAppInstalledInTeam(data) {
|
|
1201
|
+
if (!MicrosoftTeamsAppClientId) {
|
|
1202
|
+
return MicrosoftTeamsAppInstallState.Unknown;
|
|
1203
|
+
}
|
|
1204
|
+
try {
|
|
1205
|
+
const accessToken = await this.getValidAccessToken({
|
|
1206
|
+
authToken: data.authToken,
|
|
1207
|
+
projectId: data.projectId,
|
|
1208
|
+
});
|
|
1209
|
+
let nextLink = `https://graph.microsoft.com/v1.0/teams/${data.teamId}/installedApps?$expand=teamsApp`;
|
|
1210
|
+
let pageCount = 0;
|
|
1211
|
+
while (nextLink) {
|
|
1212
|
+
pageCount++;
|
|
1213
|
+
if (pageCount > MICROSOFT_TEAMS_MAX_PAGES) {
|
|
1214
|
+
logger.warn(`Stopped paginating installed apps for team ${data.teamId} after ${MICROSOFT_TEAMS_MAX_PAGES} pages.`);
|
|
1215
|
+
return MicrosoftTeamsAppInstallState.Unknown;
|
|
1216
|
+
}
|
|
1217
|
+
const response = await API.get({
|
|
1218
|
+
url: URL.fromString(nextLink),
|
|
1219
|
+
headers: {
|
|
1220
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1221
|
+
"Content-Type": "application/json",
|
|
1222
|
+
},
|
|
1223
|
+
});
|
|
1224
|
+
if (response instanceof HTTPErrorResponse) {
|
|
1225
|
+
logger.debug(`Could not read installed apps for team ${data.teamId}; treating installation as unknown.`);
|
|
1226
|
+
logger.debug(response);
|
|
1227
|
+
return MicrosoftTeamsAppInstallState.Unknown;
|
|
1228
|
+
}
|
|
1229
|
+
const installedApps = response.data["value"] || [];
|
|
1230
|
+
for (const installedApp of installedApps) {
|
|
1231
|
+
const teamsApp = installedApp["teamsApp"] || {};
|
|
1232
|
+
if (teamsApp["externalId"] === MicrosoftTeamsAppClientId) {
|
|
1233
|
+
return MicrosoftTeamsAppInstallState.Installed;
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
nextLink = response.data["@odata.nextLink"] || null;
|
|
1237
|
+
}
|
|
1238
|
+
return MicrosoftTeamsAppInstallState.NotInstalled;
|
|
1239
|
+
}
|
|
1240
|
+
catch (err) {
|
|
1241
|
+
logger.debug(`Error checking whether the OneUptime app is installed in team ${data.teamId}; treating installation as unknown.`);
|
|
1242
|
+
logger.debug(err);
|
|
1243
|
+
return MicrosoftTeamsAppInstallState.Unknown;
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1101
1246
|
/*
|
|
1102
1247
|
* Sends an adaptive card to a Teams group chat or personal (1:1) chat via a
|
|
1103
1248
|
* proactive Bot Framework message. The OneUptime app must have been added to
|
|
@@ -1566,6 +1711,7 @@ class MicrosoftTeamsUtil extends WorkspaceBase {
|
|
|
1566
1711
|
await this.captureTeamFromBotActivity({
|
|
1567
1712
|
activity: data.activity,
|
|
1568
1713
|
turnContext: data.turnContext,
|
|
1714
|
+
onlyIfMissingOrStale: true,
|
|
1569
1715
|
});
|
|
1570
1716
|
}
|
|
1571
1717
|
// If this is actually an Adaptive Card submit wrapped as a message, route to invoke handler
|
|
@@ -2965,13 +3111,93 @@ All monitoring checks are passing normally.`;
|
|
|
2965
3111
|
* (channels are not chats), so before this existed we threw away the only
|
|
2966
3112
|
* signal that tells us a proactive channel post will be accepted.
|
|
2967
3113
|
*/
|
|
3114
|
+
/*
|
|
3115
|
+
* The AAD group id for a team, which is what Graph calls the team id and what
|
|
3116
|
+
* every notification rule stores. Teams normally puts it on the activity as
|
|
3117
|
+
* channelData.team.aadGroupId; when it does not, TeamsInfo.getTeamDetails
|
|
3118
|
+
* fetches it. Returns undefined rather than throwing — a missing group id
|
|
3119
|
+
* degrades the record, it does not invalidate the install.
|
|
3120
|
+
*/
|
|
3121
|
+
static async resolveGraphTeamIdFromBotActivity(data) {
|
|
3122
|
+
var _a;
|
|
3123
|
+
const aadGroupIdOnActivity = ((_a = data.team) === null || _a === void 0 ? void 0 : _a["aadGroupId"]) || "";
|
|
3124
|
+
if (aadGroupIdOnActivity) {
|
|
3125
|
+
return aadGroupIdOnActivity;
|
|
3126
|
+
}
|
|
3127
|
+
try {
|
|
3128
|
+
const teamDetails = await TeamsInfo.getTeamDetails(data.turnContext);
|
|
3129
|
+
return (teamDetails === null || teamDetails === void 0 ? void 0 : teamDetails.aadGroupId) || undefined;
|
|
3130
|
+
}
|
|
3131
|
+
catch (err) {
|
|
3132
|
+
/*
|
|
3133
|
+
* Uninstall activities are the common case here: the bot is already out
|
|
3134
|
+
* of the team by the time we ask, so the call fails. Uninstall matches on
|
|
3135
|
+
* the thread id anyway, so this is not worth an error-level log.
|
|
3136
|
+
*/
|
|
3137
|
+
logger.debug("Could not resolve the Graph team id for a Microsoft Teams install:");
|
|
3138
|
+
logger.debug(err);
|
|
3139
|
+
return undefined;
|
|
3140
|
+
}
|
|
3141
|
+
}
|
|
3142
|
+
/*
|
|
3143
|
+
* installedTeams re-keyed by Graph team id, which is the id every caller
|
|
3144
|
+
* outside the bot handlers actually holds. Records that could not be resolved
|
|
3145
|
+
* to a group id are dropped: they cannot answer "is this team installed?" for
|
|
3146
|
+
* a notification rule, and including them under their thread id would only
|
|
3147
|
+
* invite the same confusion this replaced.
|
|
3148
|
+
*/
|
|
3149
|
+
static indexInstalledTeamsByGraphTeamId(installedTeams) {
|
|
3150
|
+
const index = {};
|
|
3151
|
+
for (const installedTeam of Object.values(installedTeams || {})) {
|
|
3152
|
+
const graphTeamId = (installedTeam === null || installedTeam === void 0 ? void 0 : installedTeam.graphTeamId) || undefined;
|
|
3153
|
+
if (!graphTeamId) {
|
|
3154
|
+
continue;
|
|
3155
|
+
}
|
|
3156
|
+
index[graphTeamId] = installedTeam;
|
|
3157
|
+
}
|
|
3158
|
+
return index;
|
|
3159
|
+
}
|
|
3160
|
+
/*
|
|
3161
|
+
* The stored record for a team in a tenant, if any, matched on either id.
|
|
3162
|
+
* Used to keep the message-driven backfill cheap.
|
|
3163
|
+
*/
|
|
3164
|
+
static async getInstalledTeamForTenant(data) {
|
|
3165
|
+
const projectAuths = await WorkspaceProjectAuthTokenService.findBy({
|
|
3166
|
+
query: {
|
|
3167
|
+
workspaceType: WorkspaceType.MicrosoftTeams,
|
|
3168
|
+
workspaceProjectId: data.tenantId,
|
|
3169
|
+
},
|
|
3170
|
+
select: {
|
|
3171
|
+
_id: true,
|
|
3172
|
+
miscData: true,
|
|
3173
|
+
},
|
|
3174
|
+
limit: LIMIT_MAX,
|
|
3175
|
+
skip: 0,
|
|
3176
|
+
props: {
|
|
3177
|
+
isRoot: true,
|
|
3178
|
+
},
|
|
3179
|
+
});
|
|
3180
|
+
for (const projectAuth of projectAuths) {
|
|
3181
|
+
const miscData = projectAuth.miscData || {};
|
|
3182
|
+
for (const existingTeam of Object.values(miscData.installedTeams || {})) {
|
|
3183
|
+
if (this.isSameInstalledTeam({
|
|
3184
|
+
team: existingTeam,
|
|
3185
|
+
graphTeamId: data.graphTeamId,
|
|
3186
|
+
teamsThreadId: data.teamsThreadId,
|
|
3187
|
+
})) {
|
|
3188
|
+
return existingTeam;
|
|
3189
|
+
}
|
|
3190
|
+
}
|
|
3191
|
+
}
|
|
3192
|
+
return null;
|
|
3193
|
+
}
|
|
2968
3194
|
static async captureTeamFromBotActivity(data) {
|
|
2969
3195
|
var _a;
|
|
2970
3196
|
try {
|
|
2971
3197
|
const channelData = data.activity["channelData"] || {};
|
|
2972
3198
|
const team = channelData["team"];
|
|
2973
|
-
const
|
|
2974
|
-
if (!
|
|
3199
|
+
const teamsThreadId = (team === null || team === void 0 ? void 0 : team["id"]) || "";
|
|
3200
|
+
if (!teamsThreadId) {
|
|
2975
3201
|
// Not a team-scoped activity (personal or group chat). Nothing to do.
|
|
2976
3202
|
return;
|
|
2977
3203
|
}
|
|
@@ -2980,19 +3206,53 @@ All monitoring checks are passing normally.`;
|
|
|
2980
3206
|
logger.debug("No tenant id found on team activity. Skipping.");
|
|
2981
3207
|
return;
|
|
2982
3208
|
}
|
|
3209
|
+
const activityServiceUrl = data.activity["serviceUrl"] ||
|
|
3210
|
+
data.turnContext.activity.serviceUrl ||
|
|
3211
|
+
undefined;
|
|
3212
|
+
/*
|
|
3213
|
+
* The backfill runs on every inbound channel message, so it must be cheap
|
|
3214
|
+
* once the team is already on record: one read, then nothing. Without this
|
|
3215
|
+
* every message meant a write, and now potentially a Bot Framework call to
|
|
3216
|
+
* resolve the group id as well. A record that is missing the group id, or
|
|
3217
|
+
* whose serviceUrl has moved, is still worth redoing.
|
|
3218
|
+
*/
|
|
3219
|
+
if (data.onlyIfMissingOrStale) {
|
|
3220
|
+
const existingTeam = await this.getInstalledTeamForTenant({
|
|
3221
|
+
tenantId: tenantId,
|
|
3222
|
+
teamsThreadId: teamsThreadId,
|
|
3223
|
+
graphTeamId: (team === null || team === void 0 ? void 0 : team["aadGroupId"]) || undefined,
|
|
3224
|
+
});
|
|
3225
|
+
if (existingTeam &&
|
|
3226
|
+
existingTeam.graphTeamId &&
|
|
3227
|
+
existingTeam.serviceUrl === activityServiceUrl) {
|
|
3228
|
+
return;
|
|
3229
|
+
}
|
|
3230
|
+
}
|
|
3231
|
+
/*
|
|
3232
|
+
* The send path looks installs up by Graph team id, so resolving it here
|
|
3233
|
+
* is what makes the record usable at all. Teams puts it on the activity
|
|
3234
|
+
* as aadGroupId most of the time; when it does not, one Bot Framework
|
|
3235
|
+
* call gets it. A record without it is still worth keeping for the
|
|
3236
|
+
* serviceUrl and for uninstall matching, it just cannot be matched to a
|
|
3237
|
+
* notification rule.
|
|
3238
|
+
*/
|
|
3239
|
+
const graphTeamId = await this.resolveGraphTeamIdFromBotActivity({
|
|
3240
|
+
team: team,
|
|
3241
|
+
turnContext: data.turnContext,
|
|
3242
|
+
});
|
|
2983
3243
|
const installedTeam = {
|
|
2984
|
-
id:
|
|
3244
|
+
id: graphTeamId || teamsThreadId,
|
|
3245
|
+
graphTeamId: graphTeamId,
|
|
3246
|
+
teamsThreadId: teamsThreadId,
|
|
2985
3247
|
name: (team === null || team === void 0 ? void 0 : team["name"]) || undefined,
|
|
2986
|
-
serviceUrl:
|
|
2987
|
-
data.turnContext.activity.serviceUrl ||
|
|
2988
|
-
undefined,
|
|
3248
|
+
serviceUrl: activityServiceUrl,
|
|
2989
3249
|
addedAt: OneUptimeDate.getCurrentDate().toISOString(),
|
|
2990
3250
|
};
|
|
2991
3251
|
await this.saveTeamToProjectAuthTokens({
|
|
2992
3252
|
tenantId: tenantId,
|
|
2993
3253
|
team: installedTeam,
|
|
2994
3254
|
});
|
|
2995
|
-
logger.debug(`Captured Microsoft Teams team install ${
|
|
3255
|
+
logger.debug(`Captured Microsoft Teams team install ${installedTeam.id} (thread ${teamsThreadId}, graph ${graphTeamId || "unresolved"}) for tenant ${tenantId}`);
|
|
2996
3256
|
}
|
|
2997
3257
|
catch (err) {
|
|
2998
3258
|
logger.error("Error capturing Microsoft Teams team from bot activity:");
|
|
@@ -3000,19 +3260,28 @@ All monitoring checks are passing normally.`;
|
|
|
3000
3260
|
}
|
|
3001
3261
|
}
|
|
3002
3262
|
static async removeTeamFromBotActivity(data) {
|
|
3003
|
-
var _a
|
|
3263
|
+
var _a;
|
|
3004
3264
|
try {
|
|
3005
3265
|
const channelData = data.activity["channelData"] || {};
|
|
3006
|
-
const
|
|
3007
|
-
const
|
|
3008
|
-
|
|
3266
|
+
const team = channelData["team"];
|
|
3267
|
+
const teamsThreadId = (team === null || team === void 0 ? void 0 : team["id"]) || "";
|
|
3268
|
+
const tenantId = ((_a = channelData["tenant"]) === null || _a === void 0 ? void 0 : _a["id"]) || "";
|
|
3269
|
+
if (!teamsThreadId || !tenantId) {
|
|
3009
3270
|
return;
|
|
3010
3271
|
}
|
|
3272
|
+
/*
|
|
3273
|
+
* Uninstall matches on both ids because we cannot know which one the
|
|
3274
|
+
* record was keyed by: the bot is already out of the team, so
|
|
3275
|
+
* getTeamDetails will not answer, and records written before this shipped
|
|
3276
|
+
* only have a thread id. aadGroupId is still on the activity often enough
|
|
3277
|
+
* to be worth passing through.
|
|
3278
|
+
*/
|
|
3011
3279
|
await this.removeTeamFromProjectAuthTokens({
|
|
3012
3280
|
tenantId: tenantId,
|
|
3013
|
-
|
|
3281
|
+
teamsThreadId: teamsThreadId,
|
|
3282
|
+
graphTeamId: (team === null || team === void 0 ? void 0 : team["aadGroupId"]) || undefined,
|
|
3014
3283
|
});
|
|
3015
|
-
logger.debug(`Removed Microsoft Teams team install ${
|
|
3284
|
+
logger.debug(`Removed Microsoft Teams team install ${teamsThreadId} for tenant ${tenantId}`);
|
|
3016
3285
|
}
|
|
3017
3286
|
catch (err) {
|
|
3018
3287
|
logger.error("Error removing Microsoft Teams team from bot activity:");
|
|
@@ -3042,7 +3311,25 @@ All monitoring checks are passing normally.`;
|
|
|
3042
3311
|
});
|
|
3043
3312
|
for (const projectAuth of projectAuths) {
|
|
3044
3313
|
const miscData = Object.assign({}, (projectAuth.miscData || {}));
|
|
3045
|
-
|
|
3314
|
+
/*
|
|
3315
|
+
* Drop any other record describing the same team before inserting. A
|
|
3316
|
+
* team captured before the group id was resolvable sits under its thread
|
|
3317
|
+
* id, and re-capturing it under the group id would otherwise leave two
|
|
3318
|
+
* records for one team — one of which can never be matched or removed.
|
|
3319
|
+
*/
|
|
3320
|
+
const installedTeams = {};
|
|
3321
|
+
for (const [key, existingTeam] of Object.entries(miscData.installedTeams || {})) {
|
|
3322
|
+
if (this.isSameInstalledTeam({
|
|
3323
|
+
team: existingTeam,
|
|
3324
|
+
graphTeamId: data.team.graphTeamId,
|
|
3325
|
+
teamsThreadId: data.team.teamsThreadId,
|
|
3326
|
+
})) {
|
|
3327
|
+
continue;
|
|
3328
|
+
}
|
|
3329
|
+
installedTeams[key] = existingTeam;
|
|
3330
|
+
}
|
|
3331
|
+
installedTeams[data.team.id] = data.team;
|
|
3332
|
+
miscData.installedTeams = installedTeams;
|
|
3046
3333
|
await WorkspaceProjectAuthTokenService.updateOneById({
|
|
3047
3334
|
id: projectAuth.id,
|
|
3048
3335
|
data: {
|
|
@@ -3054,6 +3341,28 @@ All monitoring checks are passing normally.`;
|
|
|
3054
3341
|
});
|
|
3055
3342
|
}
|
|
3056
3343
|
}
|
|
3344
|
+
/*
|
|
3345
|
+
* Whether a stored record describes the team identified by either id. Matches
|
|
3346
|
+
* on the record's explicit ids and on its key, so records written before
|
|
3347
|
+
* teamsThreadId existed — where the thread id is only in `id` — still match.
|
|
3348
|
+
* Ids are compared case-sensitively, as Microsoft returns them.
|
|
3349
|
+
*/
|
|
3350
|
+
static isSameInstalledTeam(data) {
|
|
3351
|
+
if (!data.team) {
|
|
3352
|
+
return false;
|
|
3353
|
+
}
|
|
3354
|
+
if (data.graphTeamId &&
|
|
3355
|
+
(data.team.graphTeamId === data.graphTeamId ||
|
|
3356
|
+
data.team.id === data.graphTeamId)) {
|
|
3357
|
+
return true;
|
|
3358
|
+
}
|
|
3359
|
+
if (data.teamsThreadId &&
|
|
3360
|
+
(data.team.teamsThreadId === data.teamsThreadId ||
|
|
3361
|
+
data.team.id === data.teamsThreadId)) {
|
|
3362
|
+
return true;
|
|
3363
|
+
}
|
|
3364
|
+
return false;
|
|
3365
|
+
}
|
|
3057
3366
|
static async removeTeamFromProjectAuthTokens(data) {
|
|
3058
3367
|
const projectAuths = await WorkspaceProjectAuthTokenService.findBy({
|
|
3059
3368
|
query: {
|
|
@@ -3072,11 +3381,25 @@ All monitoring checks are passing normally.`;
|
|
|
3072
3381
|
});
|
|
3073
3382
|
for (const projectAuth of projectAuths) {
|
|
3074
3383
|
const miscData = Object.assign({}, (projectAuth.miscData || {}));
|
|
3075
|
-
if (!miscData.installedTeams
|
|
3384
|
+
if (!miscData.installedTeams) {
|
|
3385
|
+
continue;
|
|
3386
|
+
}
|
|
3387
|
+
const installedTeams = {};
|
|
3388
|
+
let removedAny = false;
|
|
3389
|
+
for (const [key, existingTeam] of Object.entries(miscData.installedTeams)) {
|
|
3390
|
+
if (this.isSameInstalledTeam({
|
|
3391
|
+
team: existingTeam,
|
|
3392
|
+
graphTeamId: data.graphTeamId,
|
|
3393
|
+
teamsThreadId: data.teamsThreadId,
|
|
3394
|
+
})) {
|
|
3395
|
+
removedAny = true;
|
|
3396
|
+
continue;
|
|
3397
|
+
}
|
|
3398
|
+
installedTeams[key] = existingTeam;
|
|
3399
|
+
}
|
|
3400
|
+
if (!removedAny) {
|
|
3076
3401
|
continue;
|
|
3077
3402
|
}
|
|
3078
|
-
const installedTeams = Object.assign({}, miscData.installedTeams);
|
|
3079
|
-
delete installedTeams[data.teamId];
|
|
3080
3403
|
miscData.installedTeams = installedTeams;
|
|
3081
3404
|
await WorkspaceProjectAuthTokenService.updateOneById({
|
|
3082
3405
|
id: projectAuth.id,
|
|
@@ -3715,6 +4038,12 @@ __decorate([
|
|
|
3715
4038
|
__metadata("design:paramtypes", [Object]),
|
|
3716
4039
|
__metadata("design:returntype", Promise)
|
|
3717
4040
|
], MicrosoftTeamsUtil, "sendAdaptiveCardToChannel", null);
|
|
4041
|
+
__decorate([
|
|
4042
|
+
CaptureSpan(),
|
|
4043
|
+
__metadata("design:type", Function),
|
|
4044
|
+
__metadata("design:paramtypes", [Object]),
|
|
4045
|
+
__metadata("design:returntype", Promise)
|
|
4046
|
+
], MicrosoftTeamsUtil, "isAppInstalledInTeam", null);
|
|
3718
4047
|
__decorate([
|
|
3719
4048
|
CaptureSpan(),
|
|
3720
4049
|
__metadata("design:type", Function),
|