@oneuptime/common 11.7.0 → 11.7.2
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/DashboardDomain.ts +1 -0
- package/Models/DatabaseModels/Incident.ts +2 -0
- package/Models/DatabaseModels/IncidentEpisode.ts +1 -0
- package/Models/DatabaseModels/IncidentEpisodePublicNote.ts +1 -0
- package/Models/DatabaseModels/IncidentEpisodeStateTimeline.ts +1 -0
- package/Models/DatabaseModels/IncidentPublicNote.ts +1 -0
- package/Models/DatabaseModels/IncidentStateTimeline.ts +1 -0
- package/Models/DatabaseModels/Monitor.ts +1 -0
- package/Models/DatabaseModels/MonitorStatusTimeline.ts +1 -0
- package/Models/DatabaseModels/NetworkSite.ts +1 -0
- package/Models/DatabaseModels/NetworkSiteStatusTimeline.ts +1 -0
- package/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.ts +1 -0
- package/Models/DatabaseModels/OnCallDutyPolicySchedule.ts +2 -0
- package/Models/DatabaseModels/Probe.ts +13 -13
- package/Models/DatabaseModels/ScheduledMaintenance.ts +1 -0
- package/Models/DatabaseModels/ScheduledMaintenancePublicNote.ts +1 -0
- package/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.ts +1 -0
- package/Models/DatabaseModels/ScheduledMaintenanceTemplate.ts +1 -0
- package/Models/DatabaseModels/StatusPage.ts +1 -0
- package/Models/DatabaseModels/StatusPageAnnouncement.ts +1 -0
- package/Models/DatabaseModels/StatusPageDomain.ts +1 -0
- package/Models/DatabaseModels/WorkspaceNotificationSummary.ts +1 -0
- package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +11 -0
- package/Server/API/BaseAPI.ts +17 -1
- package/Server/API/CommonAPI.ts +32 -0
- package/Server/API/MicrosoftTeamsAPI.ts +99 -2
- package/Server/API/ProbeAPI.ts +2 -0
- package/Server/API/SlackAPI.ts +62 -0
- package/Server/API/StatusPageAPI.ts +157 -192
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785140242697-AddHotQueryIndexes.ts +89 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785148065137-AddHotQueryIndexesSecondPass.ts +61 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1785240000000-RepairCrossProjectMonitorStatusReferences.ts +280 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Services/DatabaseService.ts +11 -3
- package/Server/Services/MonitorGroupService.ts +145 -0
- package/Server/Services/MonitorService.ts +231 -30
- package/Server/Services/ProbeService.ts +319 -16
- package/Server/Services/StatusPageService.ts +72 -42
- package/Server/Services/WorkspaceNotificationRuleService.ts +232 -2
- package/Server/Utils/Database/PostgresErrorTranslator.ts +131 -0
- package/Server/Utils/Monitor/MonitorResource.ts +88 -35
- package/Server/Utils/Monitor/MonitorStatusTimeline.ts +21 -1
- package/Server/Utils/Monitor/MonitorStepsProjectValidator.ts +158 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +706 -6
- package/Tests/Models/DatabaseModels/ProbeColumnAccessControl.test.ts +103 -0
- package/Tests/Server/API/BaseAPIUpdateNoOp.test.ts +135 -0
- package/Tests/Server/API/CommonAPIAuthGuard.test.ts +317 -0
- package/Tests/Server/API/MicrosoftTeamsManifest.test.ts +228 -0
- package/Tests/Server/API/ProbeAPI.test.ts +6 -0
- package/Tests/Server/API/ZZVerifyChatsAuth.test.ts +167 -0
- package/Tests/Server/Services/AddHotQueryIndexesMigration.test.ts +255 -0
- package/Tests/Server/Services/AddHotQueryIndexesSecondPassMigration.test.ts +258 -0
- package/Tests/Server/Services/DatabaseServiceSanitizeUpdateData.test.ts +1 -1
- package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +121 -0
- package/Tests/Server/Services/HeartbeatWriteFastPathSafety.test.ts +200 -0
- package/Tests/Server/Services/HookFreeWriteSafetySecondPass.test.ts +181 -0
- package/Tests/Server/Services/MonitorGroupServiceBatchedStatuses.test.ts +513 -0
- package/Tests/Server/Services/MonitorResourceProbeAgreementReuse.test.ts +492 -0
- package/Tests/Server/Services/MonitorServiceProbeSelection.test.ts +401 -0
- package/Tests/Server/Services/MonitorStatusTimelineFastPath.test.ts +453 -0
- package/Tests/Server/Services/ProbeAuthKeyCacheAndHeartbeat.test.ts +679 -0
- package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +3 -3
- package/Tests/Server/Services/StatusPageDomainResolutionCache.test.ts +245 -0
- package/Tests/Server/Services/StatusPageOverviewTimelineWindow.test.ts +283 -0
- package/Tests/Server/Services/StatusPageServiceMcp.test.ts +17 -1
- package/Tests/Server/Services/StatusPageServiceMonitorGroupBatching.test.ts +331 -0
- package/Tests/Server/Services/UserOnCallLogClaimNotificationRule.test.ts +12 -12
- package/Tests/Server/Services/WorkspaceNotificationRuleChats.test.ts +1390 -0
- package/Tests/Server/Utils/AI/Insights/InsightFixRouting.test.ts +4 -4
- package/Tests/Server/Utils/AI/Insights/InsightScanner.test.ts +2 -2
- package/Tests/Server/Utils/AI/Insights/InsightStore.test.ts +1 -3
- package/Tests/Server/Utils/AI/Insights/InsightStoreHardening.test.ts +1 -3
- package/Tests/Server/Utils/AI/Insights/InsightTriage.test.ts +1 -1
- package/Tests/Server/Utils/AI/Insights/InsightTriageRunner.test.ts +5 -5
- package/Tests/Server/Utils/Alert/AlertPrivacyFilter.test.ts +187 -0
- package/Tests/Server/Utils/AlertEpisode/AlertEpisodePrivacyFilter.test.ts +170 -0
- package/Tests/Server/Utils/Database/PostgresErrorTranslator.test.ts +125 -0
- package/Tests/Server/Utils/Incident/IncidentPrivacyFilter.test.ts +264 -0
- package/Tests/Server/Utils/IncidentEpisode/IncidentEpisodePrivacyFilter.test.ts +175 -0
- package/Tests/Server/Utils/Monitor/MonitorStepsProjectValidator.test.ts +181 -0
- package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +1 -1
- package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +2 -2
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelsList.test.ts +341 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsChats.test.ts +2175 -0
- package/Tests/Server/Utils/Workspace/SlackChannelsList.test.ts +585 -0
- package/Tests/Types/Billing/MeteredPlan.test.ts +46 -0
- package/Tests/Types/DateUserTimezone.test.ts +205 -0
- package/Tests/Types/DateUserTimezoneOverridesBrowser.test.ts +73 -0
- package/Tests/Types/Workspace/NotificationRules/NotificationRuleCondition.test.ts +219 -1
- package/Tests/UI/Components/BulkUpdateForm.test.tsx +174 -0
- package/Tests/UI/Components/CardModelDetailEdit.test.tsx +315 -0
- package/Tests/UI/Components/ModelDetailSelect.test.tsx +229 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableBulkSelectAll.test.tsx +1258 -0
- package/Tests/UI/Components/ModelTableExportFromColumns.test.ts +153 -0
- package/Tests/UI/Components/MonacoLoader.test.ts +67 -0
- package/Tests/UI/Components/MonacoRuntime.test.ts +121 -0
- package/Tests/UI/Components/TableBulkCsvExport.test.tsx +212 -3
- package/Tests/UI/Components/TimePicker/TimePicker.test.tsx +11 -0
- package/Tests/UI/Utils/Project.test.ts +809 -0
- package/Tests/UI/Utils/TableColumnsToCsv.test.ts +360 -0
- package/Tests/Utils/Alerts/AlertMetricType.test.ts +143 -0
- package/Tests/Utils/Dashboard/VariableUrlState.test.ts +219 -0
- package/Tests/Utils/Incident/IncidentMetricType.test.ts +174 -0
- package/Tests/Utils/Monitor/MonitorProbeSelectionUtil.test.ts +145 -0
- package/Tests/Utils/StatusPage/ResourceUptime.test.ts +263 -0
- package/Types/Date.ts +119 -50
- package/Types/Workspace/NotificationRules/BaseNotificationRule.ts +4 -0
- package/Types/Workspace/NotificationRules/NotificationRuleCondition.ts +25 -10
- package/Types/Workspace/WorkspaceMessagePayload.ts +1 -0
- package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +63 -8
- package/UI/Components/CodeEditor/CodeEditor.tsx +3 -0
- package/UI/Components/CodeEditor/MonacoLoader.ts +36 -0
- package/UI/Components/Forms/Fields/FormField.tsx +13 -3
- package/UI/Components/Forms/ModelForm.tsx +41 -18
- package/UI/Components/Input/Input.tsx +6 -1
- package/UI/Components/ModelDetail/CardModelDetail.tsx +23 -1
- package/UI/Components/ModelDetail/ModelDetail.tsx +46 -1
- package/UI/Components/ModelTable/BaseModelTable.tsx +300 -30
- package/UI/Components/ModelTable/Column.ts +12 -0
- package/UI/Components/ModelTable/ExportFromColumns.ts +57 -0
- package/UI/Components/Navbar/NavBar.tsx +66 -1
- package/UI/Components/Table/Table.tsx +52 -13
- package/UI/Components/Table/Types/Column.ts +18 -0
- package/UI/Components/TimePicker/TimePicker.tsx +8 -4
- package/UI/Utils/Project.ts +214 -18
- package/UI/Utils/TableColumnsToCsv.ts +86 -6
- package/UI/Utils/User.ts +19 -0
- package/UI/esbuild-config.js +34 -0
- package/Utils/Monitor/MonitorProbeSelectionUtil.ts +72 -0
- package/build/dist/Models/DatabaseModels/DashboardDomain.js +1 -0
- package/build/dist/Models/DatabaseModels/DashboardDomain.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Incident.js +2 -0
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisode.js +1 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js +1 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentPublicNote.js +1 -0
- package/build/dist/Models/DatabaseModels/IncidentPublicNote.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Monitor.js +1 -0
- package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MonitorStatusTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/MonitorStatusTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkSite.js +1 -0
- package/build/dist/Models/DatabaseModels/NetworkSite.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkSiteStatusTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/NetworkSiteStatusTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js +1 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js +2 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Probe.js +13 -13
- package/build/dist/Models/DatabaseModels/Probe.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +1 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js +1 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js +1 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplate.js +1 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplate.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPage.js +1 -0
- package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js +1 -0
- package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageDomain.js +1 -0
- package/build/dist/Models/DatabaseModels/StatusPageDomain.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkspaceNotificationSummary.js +1 -0
- package/build/dist/Models/DatabaseModels/WorkspaceNotificationSummary.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +12 -1
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/CommonAPI.js +21 -0
- package/build/dist/Server/API/CommonAPI.js.map +1 -1
- package/build/dist/Server/API/MicrosoftTeamsAPI.js +72 -2
- package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
- package/build/dist/Server/API/ProbeAPI.js +2 -0
- package/build/dist/Server/API/ProbeAPI.js.map +1 -1
- package/build/dist/Server/API/SlackAPI.js +44 -0
- package/build/dist/Server/API/SlackAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +98 -152
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785140242697-AddHotQueryIndexes.js +36 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785140242697-AddHotQueryIndexes.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785148065137-AddHotQueryIndexesSecondPass.js +26 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785148065137-AddHotQueryIndexesSecondPass.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785240000000-RepairCrossProjectMonitorStatusReferences.js +254 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785240000000-RepairCrossProjectMonitorStatusReferences.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +10 -2
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/MonitorGroupService.js +118 -0
- package/build/dist/Server/Services/MonitorGroupService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +198 -24
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/ProbeService.js +238 -9
- package/build/dist/Server/Services/ProbeService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageService.js +46 -39
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +178 -3
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js +80 -0
- package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +67 -29
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js +31 -14
- package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js +117 -0
- package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +549 -7
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Types/Date.js +106 -35
- package/build/dist/Types/Date.js.map +1 -1
- package/build/dist/Types/Workspace/NotificationRules/NotificationRuleCondition.js +17 -7
- package/build/dist/Types/Workspace/NotificationRules/NotificationRuleCondition.js.map +1 -1
- package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js +37 -11
- package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js.map +1 -1
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js +2 -0
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
- package/build/dist/UI/Components/CodeEditor/MonacoLoader.js +34 -0
- package/build/dist/UI/Components/CodeEditor/MonacoLoader.js.map +1 -0
- package/build/dist/UI/Components/Forms/Fields/FormField.js +11 -3
- package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
- package/build/dist/UI/Components/Forms/ModelForm.js +37 -17
- package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
- package/build/dist/UI/Components/Input/Input.js +6 -1
- package/build/dist/UI/Components/Input/Input.js.map +1 -1
- package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +22 -1
- package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
- package/build/dist/UI/Components/ModelDetail/ModelDetail.js +31 -1
- package/build/dist/UI/Components/ModelDetail/ModelDetail.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +234 -21
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/ExportFromColumns.js +30 -0
- package/build/dist/UI/Components/ModelTable/ExportFromColumns.js.map +1 -0
- package/build/dist/UI/Components/Navbar/NavBar.js +39 -1
- package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
- package/build/dist/UI/Components/Table/Table.js +31 -11
- package/build/dist/UI/Components/Table/Table.js.map +1 -1
- package/build/dist/UI/Components/TimePicker/TimePicker.js +4 -4
- package/build/dist/UI/Components/TimePicker/TimePicker.js.map +1 -1
- package/build/dist/UI/Utils/Project.js +161 -15
- package/build/dist/UI/Utils/Project.js.map +1 -1
- package/build/dist/UI/Utils/TableColumnsToCsv.js +67 -6
- package/build/dist/UI/Utils/TableColumnsToCsv.js.map +1 -1
- package/build/dist/UI/Utils/User.js +19 -0
- package/build/dist/UI/Utils/User.js.map +1 -1
- package/build/dist/Utils/Monitor/MonitorProbeSelectionUtil.js +52 -0
- package/build/dist/Utils/Monitor/MonitorProbeSelectionUtil.js.map +1 -0
- package/package.json +4 -3
- package/Server/Infrastructure/Postgres/SchemaMigrations/1773414578773-MigrationName.ts +0 -79
- package/Server/Infrastructure/Postgres/SchemaMigrations/1773500000000-MigrationName.ts +0 -41
- package/Server/Infrastructure/Postgres/SchemaMigrations/1776886248361-MigrationName.ts +0 -17
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1773414578773-MigrationName.js +0 -34
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1773414578773-MigrationName.js.map +0 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1773500000000-MigrationName.js +0 -22
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1773500000000-MigrationName.js.map +0 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776886248361-MigrationName.js +0 -12
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776886248361-MigrationName.js.map +0 -1
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import { describe, expect, test, afterEach, beforeEach } from "@jest/globals";
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* Extensive tests for MicrosoftTeamsUtil.getAllWorkspaceChannels — the
|
|
5
|
+
* Microsoft Graph call behind the dashboard's "browse Teams channels"
|
|
6
|
+
* endpoint (GET /microsoft-teams/channels). It must:
|
|
7
|
+
*
|
|
8
|
+
* - resolve a Graph access token via getValidAccessToken,
|
|
9
|
+
* - GET https://graph.microsoft.com/v1.0/teams/{teamId}/channels with a
|
|
10
|
+
* Bearer header,
|
|
11
|
+
* - map the response's value[] into a Dictionary<WorkspaceChannel> keyed
|
|
12
|
+
* by channel id with name = displayName and
|
|
13
|
+
* workspaceType = MicrosoftTeams,
|
|
14
|
+
* - rethrow HTTPErrorResponse results.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
jest.mock("../../../../Server/EnvironmentConfig", () => {
|
|
18
|
+
return {
|
|
19
|
+
...(jest.requireActual("../../../../Server/EnvironmentConfig") as Record<
|
|
20
|
+
string,
|
|
21
|
+
unknown
|
|
22
|
+
>),
|
|
23
|
+
MicrosoftTeamsAppClientId: "11111111-2222-3333-4444-555555555555",
|
|
24
|
+
MicrosoftTeamsAppClientSecret: "test-secret",
|
|
25
|
+
MicrosoftTeamsAppTenantId: "test-tenant",
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
/*
|
|
30
|
+
* Same botbuilder module factory as MicrosoftTeamsChats.test.ts — the
|
|
31
|
+
* repo-wide manual mock does not expose everything MicrosoftTeams.ts
|
|
32
|
+
* touches at import time.
|
|
33
|
+
*/
|
|
34
|
+
jest.mock("botbuilder", () => {
|
|
35
|
+
return {
|
|
36
|
+
CloudAdapter: class CloudAdapter {},
|
|
37
|
+
ConfigurationBotFrameworkAuthentication: class ConfigurationBotFrameworkAuthentication {},
|
|
38
|
+
TeamsActivityHandler: class TeamsActivityHandler {},
|
|
39
|
+
TurnContext: class TurnContext {},
|
|
40
|
+
ActivityHandler: class ActivityHandler {},
|
|
41
|
+
MessageFactory: {
|
|
42
|
+
text: jest.fn(),
|
|
43
|
+
attachment: jest.fn(),
|
|
44
|
+
},
|
|
45
|
+
CardFactory: { heroCard: jest.fn() },
|
|
46
|
+
TeamsInfo: {
|
|
47
|
+
getMembers: jest.fn(),
|
|
48
|
+
getPagedMembers: jest.fn(),
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
import MicrosoftTeamsUtil from "../../../../Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams";
|
|
54
|
+
import { WorkspaceChannel } from "../../../../Server/Utils/Workspace/WorkspaceBase";
|
|
55
|
+
import API from "../../../../Utils/API";
|
|
56
|
+
import HTTPResponse from "../../../../Types/API/HTTPResponse";
|
|
57
|
+
import HTTPErrorResponse from "../../../../Types/API/HTTPErrorResponse";
|
|
58
|
+
import URL from "../../../../Types/API/URL";
|
|
59
|
+
import Headers from "../../../../Types/API/Headers";
|
|
60
|
+
import { JSONObject } from "../../../../Types/JSON";
|
|
61
|
+
import Dictionary from "../../../../Types/Dictionary";
|
|
62
|
+
import ObjectID from "../../../../Types/ObjectID";
|
|
63
|
+
import WorkspaceType from "../../../../Types/Workspace/WorkspaceType";
|
|
64
|
+
import { MessageFactory, CardFactory, TeamsInfo } from "botbuilder";
|
|
65
|
+
|
|
66
|
+
const GRAPH_TOKEN: string = "graph-token";
|
|
67
|
+
const AUTH_TOKEN: string = "stored-auth-token";
|
|
68
|
+
const TEAM_ID: string = "team-42";
|
|
69
|
+
|
|
70
|
+
interface CapturedGetCall {
|
|
71
|
+
url: URL;
|
|
72
|
+
headers: Headers;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function mockAccessToken(token?: string): jest.SpyInstance {
|
|
76
|
+
return jest
|
|
77
|
+
.spyOn(MicrosoftTeamsUtil, "getValidAccessToken")
|
|
78
|
+
.mockResolvedValue(token === undefined ? GRAPH_TOKEN : token);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function mockGraphResponse(data: JSONObject): jest.SpyInstance {
|
|
82
|
+
return jest
|
|
83
|
+
.spyOn(API, "get")
|
|
84
|
+
.mockResolvedValue(new HTTPResponse<JSONObject>(200, data, {}));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function channelJson(id: string, displayName?: string): JSONObject {
|
|
88
|
+
const channel: JSONObject = { id: id };
|
|
89
|
+
if (displayName !== undefined) {
|
|
90
|
+
channel["displayName"] = displayName;
|
|
91
|
+
}
|
|
92
|
+
return channel;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async function callGetAllWorkspaceChannels(data?: {
|
|
96
|
+
authToken?: string | undefined;
|
|
97
|
+
projectId?: ObjectID | undefined;
|
|
98
|
+
teamId?: string | undefined;
|
|
99
|
+
}): Promise<Dictionary<WorkspaceChannel>> {
|
|
100
|
+
return MicrosoftTeamsUtil.getAllWorkspaceChannels({
|
|
101
|
+
authToken: data?.authToken || AUTH_TOKEN,
|
|
102
|
+
projectId: data?.projectId || ObjectID.generate(),
|
|
103
|
+
teamId: data?.teamId || TEAM_ID,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
afterEach(() => {
|
|
108
|
+
jest.restoreAllMocks();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
/*
|
|
112
|
+
* The botbuilder module mock's jest.fn()s are shared across test files in
|
|
113
|
+
* this suite run — jest.spyOn on an existing mock returns the same
|
|
114
|
+
* function, so call history and mockResolvedValueOnce queues leak between
|
|
115
|
+
* tests unless reset here.
|
|
116
|
+
*/
|
|
117
|
+
beforeEach(() => {
|
|
118
|
+
(MessageFactory.text as jest.Mock).mockReset();
|
|
119
|
+
(MessageFactory.attachment as jest.Mock).mockReset();
|
|
120
|
+
(CardFactory.heroCard as jest.Mock).mockReset();
|
|
121
|
+
(TeamsInfo.getMembers as jest.Mock).mockReset();
|
|
122
|
+
(TeamsInfo.getPagedMembers as jest.Mock).mockReset();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
describe("MicrosoftTeamsUtil.getAllWorkspaceChannels", () => {
|
|
126
|
+
test("maps id and displayName into a WorkspaceChannel", async () => {
|
|
127
|
+
mockAccessToken();
|
|
128
|
+
mockGraphResponse({
|
|
129
|
+
value: [channelJson("19:general@thread.tacv2", "General")],
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const channels: Dictionary<WorkspaceChannel> =
|
|
133
|
+
await callGetAllWorkspaceChannels();
|
|
134
|
+
|
|
135
|
+
expect(channels["19:general@thread.tacv2"]).toEqual({
|
|
136
|
+
id: "19:general@thread.tacv2",
|
|
137
|
+
name: "General",
|
|
138
|
+
workspaceType: WorkspaceType.MicrosoftTeams,
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test("keys the dictionary by channel id, not by name", async () => {
|
|
143
|
+
mockAccessToken();
|
|
144
|
+
mockGraphResponse({
|
|
145
|
+
value: [channelJson("19:ops@thread.tacv2", "Ops")],
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const channels: Dictionary<WorkspaceChannel> =
|
|
149
|
+
await callGetAllWorkspaceChannels();
|
|
150
|
+
|
|
151
|
+
expect(Object.keys(channels)).toEqual(["19:ops@thread.tacv2"]);
|
|
152
|
+
expect(channels["Ops"]).toBeUndefined();
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test("calls the exact Graph URL for the given teamId", async () => {
|
|
156
|
+
mockAccessToken();
|
|
157
|
+
const getSpy: jest.SpyInstance = mockGraphResponse({ value: [] });
|
|
158
|
+
|
|
159
|
+
await callGetAllWorkspaceChannels({ teamId: "my-team-id" });
|
|
160
|
+
|
|
161
|
+
expect(getSpy).toHaveBeenCalledTimes(1);
|
|
162
|
+
const callArg: CapturedGetCall = getSpy.mock
|
|
163
|
+
.calls[0]?.[0] as CapturedGetCall;
|
|
164
|
+
expect(callArg.url.toString()).toBe(
|
|
165
|
+
"https://graph.microsoft.com/v1.0/teams/my-team-id/channels",
|
|
166
|
+
);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test("sends the Bearer token from getValidAccessToken plus a JSON content type header", async () => {
|
|
170
|
+
mockAccessToken("fresh-token-abc");
|
|
171
|
+
const getSpy: jest.SpyInstance = mockGraphResponse({ value: [] });
|
|
172
|
+
|
|
173
|
+
await callGetAllWorkspaceChannels();
|
|
174
|
+
|
|
175
|
+
const callArg: CapturedGetCall = getSpy.mock
|
|
176
|
+
.calls[0]?.[0] as CapturedGetCall;
|
|
177
|
+
expect(callArg.headers).toEqual({
|
|
178
|
+
Authorization: "Bearer fresh-token-abc",
|
|
179
|
+
"Content-Type": "application/json",
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test("passes the caller's authToken and projectId to getValidAccessToken", async () => {
|
|
184
|
+
const tokenSpy: jest.SpyInstance = mockAccessToken();
|
|
185
|
+
mockGraphResponse({ value: [] });
|
|
186
|
+
const projectId: ObjectID = ObjectID.generate();
|
|
187
|
+
|
|
188
|
+
await callGetAllWorkspaceChannels({
|
|
189
|
+
authToken: "caller-token",
|
|
190
|
+
projectId: projectId,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
expect(tokenSpy).toHaveBeenCalledTimes(1);
|
|
194
|
+
expect(tokenSpy).toHaveBeenCalledWith({
|
|
195
|
+
authToken: "caller-token",
|
|
196
|
+
projectId: projectId,
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
test("empty value[] returns an empty dictionary", async () => {
|
|
201
|
+
mockAccessToken();
|
|
202
|
+
mockGraphResponse({ value: [] });
|
|
203
|
+
|
|
204
|
+
const channels: Dictionary<WorkspaceChannel> =
|
|
205
|
+
await callGetAllWorkspaceChannels();
|
|
206
|
+
|
|
207
|
+
expect(channels).toEqual({});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
test("missing value key returns an empty dictionary", async () => {
|
|
211
|
+
mockAccessToken();
|
|
212
|
+
mockGraphResponse({});
|
|
213
|
+
|
|
214
|
+
const channels: Dictionary<WorkspaceChannel> =
|
|
215
|
+
await callGetAllWorkspaceChannels();
|
|
216
|
+
|
|
217
|
+
expect(channels).toEqual({});
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
test("HTTPErrorResponse from the Graph API is rethrown as-is", async () => {
|
|
221
|
+
mockAccessToken();
|
|
222
|
+
const errorResponse: HTTPErrorResponse = new HTTPErrorResponse(
|
|
223
|
+
403,
|
|
224
|
+
{ error: "Forbidden" },
|
|
225
|
+
{},
|
|
226
|
+
);
|
|
227
|
+
jest.spyOn(API, "get").mockResolvedValue(errorResponse);
|
|
228
|
+
|
|
229
|
+
await expect(callGetAllWorkspaceChannels()).rejects.toBe(errorResponse);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
test("a rejected API.get promise (network error) propagates", async () => {
|
|
233
|
+
mockAccessToken();
|
|
234
|
+
jest
|
|
235
|
+
.spyOn(API, "get")
|
|
236
|
+
.mockRejectedValue(new Error("socket hang up") as never);
|
|
237
|
+
|
|
238
|
+
await expect(callGetAllWorkspaceChannels()).rejects.toThrow(
|
|
239
|
+
"socket hang up",
|
|
240
|
+
);
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
test("channel with a missing displayName is kept with an undefined name (pins current behavior)", async () => {
|
|
244
|
+
mockAccessToken();
|
|
245
|
+
mockGraphResponse({
|
|
246
|
+
value: [
|
|
247
|
+
channelJson("19:noname@thread.tacv2"),
|
|
248
|
+
channelJson("19:named@thread.tacv2", "Named"),
|
|
249
|
+
],
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
const channels: Dictionary<WorkspaceChannel> =
|
|
253
|
+
await callGetAllWorkspaceChannels();
|
|
254
|
+
|
|
255
|
+
/*
|
|
256
|
+
* The mapper casts displayName straight to string without a fallback,
|
|
257
|
+
* so a Graph channel without displayName produces name === undefined.
|
|
258
|
+
* If this ever becomes a real problem for consumers, fix the source —
|
|
259
|
+
* this test just pins what the code does today.
|
|
260
|
+
*/
|
|
261
|
+
expect(Object.keys(channels)).toHaveLength(2);
|
|
262
|
+
expect(channels["19:noname@thread.tacv2"]?.name).toBeUndefined();
|
|
263
|
+
expect(channels["19:named@thread.tacv2"]?.name).toBe("Named");
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
test("multiple channels are all present and correctly mapped", async () => {
|
|
267
|
+
mockAccessToken();
|
|
268
|
+
mockGraphResponse({
|
|
269
|
+
value: [
|
|
270
|
+
channelJson("19:general@thread.tacv2", "General"),
|
|
271
|
+
channelJson("19:ops@thread.tacv2", "Ops War Room"),
|
|
272
|
+
channelJson("19:eng@thread.tacv2", "Engineering"),
|
|
273
|
+
],
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
const channels: Dictionary<WorkspaceChannel> =
|
|
277
|
+
await callGetAllWorkspaceChannels();
|
|
278
|
+
|
|
279
|
+
expect(Object.keys(channels)).toHaveLength(3);
|
|
280
|
+
expect(channels["19:general@thread.tacv2"]?.name).toBe("General");
|
|
281
|
+
expect(channels["19:ops@thread.tacv2"]?.name).toBe("Ops War Room");
|
|
282
|
+
expect(channels["19:eng@thread.tacv2"]?.name).toBe("Engineering");
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
test("workspaceType is MicrosoftTeams on every returned entry", async () => {
|
|
286
|
+
mockAccessToken();
|
|
287
|
+
mockGraphResponse({
|
|
288
|
+
value: [
|
|
289
|
+
channelJson("19:a@thread.tacv2", "A"),
|
|
290
|
+
channelJson("19:b@thread.tacv2", "B"),
|
|
291
|
+
channelJson("19:c@thread.tacv2", "C"),
|
|
292
|
+
],
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
const channels: Dictionary<WorkspaceChannel> =
|
|
296
|
+
await callGetAllWorkspaceChannels();
|
|
297
|
+
|
|
298
|
+
expect(Object.keys(channels)).toHaveLength(3);
|
|
299
|
+
for (const channel of Object.values(channels)) {
|
|
300
|
+
expect(channel.workspaceType).toBe(WorkspaceType.MicrosoftTeams);
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
test("duplicate channel ids collapse to the LAST occurrence (dictionary upsert, pins current behavior)", async () => {
|
|
305
|
+
mockAccessToken();
|
|
306
|
+
mockGraphResponse({
|
|
307
|
+
value: [
|
|
308
|
+
channelJson("19:dup@thread.tacv2", "First name"),
|
|
309
|
+
channelJson("19:dup@thread.tacv2", "Second name"),
|
|
310
|
+
],
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
const channels: Dictionary<WorkspaceChannel> =
|
|
314
|
+
await callGetAllWorkspaceChannels();
|
|
315
|
+
|
|
316
|
+
expect(Object.keys(channels)).toHaveLength(1);
|
|
317
|
+
expect(channels["19:dup@thread.tacv2"]?.name).toBe("Second name");
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
test("API.get is called exactly once per invocation", async () => {
|
|
321
|
+
mockAccessToken();
|
|
322
|
+
const getSpy: jest.SpyInstance = mockGraphResponse({ value: [] });
|
|
323
|
+
|
|
324
|
+
await callGetAllWorkspaceChannels();
|
|
325
|
+
await callGetAllWorkspaceChannels();
|
|
326
|
+
|
|
327
|
+
expect(getSpy).toHaveBeenCalledTimes(2);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
test("getValidAccessToken failure short-circuits before any Graph call", async () => {
|
|
331
|
+
jest
|
|
332
|
+
.spyOn(MicrosoftTeamsUtil, "getValidAccessToken")
|
|
333
|
+
.mockRejectedValue(new Error("token refresh failed") as never);
|
|
334
|
+
const getSpy: jest.SpyInstance = jest.spyOn(API, "get");
|
|
335
|
+
|
|
336
|
+
await expect(callGetAllWorkspaceChannels()).rejects.toThrow(
|
|
337
|
+
"token refresh failed",
|
|
338
|
+
);
|
|
339
|
+
expect(getSpy).not.toHaveBeenCalled();
|
|
340
|
+
});
|
|
341
|
+
});
|