@oneuptime/common 8.0.5144 → 8.0.5151
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/WorkspaceProjectAuthToken.ts +8 -1
- package/Server/API/BaseAPI.ts +18 -6
- package/Server/Services/WorkspaceNotificationRuleService.ts +7 -0
- package/Server/Utils/Workspace/Slack/Actions/Incident.ts +1 -0
- package/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.ts +1 -0
- package/Server/Utils/Workspace/Slack/Slack.ts +268 -38
- package/Server/Utils/Workspace/Workspace.ts +3 -0
- package/Server/Utils/Workspace/WorkspaceBase.ts +12 -0
- package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +18 -6
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +7 -0
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js +1 -0
- package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.js +1 -0
- package/build/dist/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js +213 -28
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Workspace.js +2 -0
- package/build/dist/Server/Utils/Workspace/Workspace.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/WorkspaceBase.js +2 -0
- package/build/dist/Server/Utils/Workspace/WorkspaceBase.js.map +1 -1
- package/package.json +1 -1
|
@@ -18,13 +18,20 @@ import WorkspaceType from "../../Types/Workspace/WorkspaceType";
|
|
|
18
18
|
import Permission from "../../Types/Permission";
|
|
19
19
|
|
|
20
20
|
export interface MiscData {
|
|
21
|
-
[key: string]:
|
|
21
|
+
[key: string]: any;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export interface SlackMiscData extends MiscData {
|
|
25
25
|
teamId: string;
|
|
26
26
|
teamName: string;
|
|
27
27
|
botUserId: string;
|
|
28
|
+
channelCache?: {
|
|
29
|
+
[channelName: string]: {
|
|
30
|
+
id: string;
|
|
31
|
+
name: string;
|
|
32
|
+
lastUpdated: string;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
28
35
|
}
|
|
29
36
|
|
|
30
37
|
@TenantColumn("projectId")
|
package/Server/API/BaseAPI.ts
CHANGED
|
@@ -235,13 +235,25 @@ export default class BaseAPI<
|
|
|
235
235
|
): Promise<void> {
|
|
236
236
|
await this.onBeforeList(req, res);
|
|
237
237
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
238
|
+
// Extract pagination parameters from query or body (for POST requests)
|
|
239
|
+
// Support both 'skip' and 'offset' parameters (offset is alias for skip)
|
|
240
|
+
let skipValue: number = 0;
|
|
241
|
+
let limitValue: number = DEFAULT_LIMIT;
|
|
242
|
+
|
|
243
|
+
if (req.query["skip"]) {
|
|
244
|
+
skipValue = parseInt(req.query["skip"] as string, 10) || 0;
|
|
245
|
+
} else if (req.body && req.body["skip"] !== undefined) {
|
|
246
|
+
skipValue = parseInt(req.body["skip"] as string, 10) || 0;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (req.query["limit"]) {
|
|
250
|
+
limitValue = parseInt(req.query["limit"] as string, 10) || DEFAULT_LIMIT;
|
|
251
|
+
} else if (req.body && req.body["limit"] !== undefined) {
|
|
252
|
+
limitValue = parseInt(req.body["limit"] as string, 10) || DEFAULT_LIMIT;
|
|
253
|
+
}
|
|
241
254
|
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
: new PositiveNumber(DEFAULT_LIMIT);
|
|
255
|
+
const skip: PositiveNumber = new PositiveNumber(skipValue);
|
|
256
|
+
const limit: PositiveNumber = new PositiveNumber(limitValue);
|
|
245
257
|
|
|
246
258
|
if (limit.toNumber() > LIMIT_PER_PROJECT) {
|
|
247
259
|
throw new BadRequestException(
|
|
@@ -214,6 +214,7 @@ export class Service extends DatabaseService<WorkspaceNotificationRule> {
|
|
|
214
214
|
).doesChannelExist({
|
|
215
215
|
authToken: projectAuthToken,
|
|
216
216
|
channelName: channelName,
|
|
217
|
+
projectId: data.projectId,
|
|
217
218
|
});
|
|
218
219
|
|
|
219
220
|
if (!channelExists) {
|
|
@@ -459,6 +460,7 @@ export class Service extends DatabaseService<WorkspaceNotificationRule> {
|
|
|
459
460
|
workspaceType: workspaceType,
|
|
460
461
|
}),
|
|
461
462
|
sendMessageBeforeArchiving: data.sendMessageBeforeArchiving,
|
|
463
|
+
projectId: data.projectId,
|
|
462
464
|
});
|
|
463
465
|
}
|
|
464
466
|
}
|
|
@@ -1032,6 +1034,7 @@ export class Service extends DatabaseService<WorkspaceNotificationRule> {
|
|
|
1032
1034
|
} as WorkspacePayloadMarkdown,
|
|
1033
1035
|
],
|
|
1034
1036
|
},
|
|
1037
|
+
projectId: data.projectId,
|
|
1035
1038
|
});
|
|
1036
1039
|
} catch (e) {
|
|
1037
1040
|
logger.error("Error in sending message to channel");
|
|
@@ -1059,6 +1062,7 @@ export class Service extends DatabaseService<WorkspaceNotificationRule> {
|
|
|
1059
1062
|
}),
|
|
1060
1063
|
workspaceUserIds: workspaceUserIds,
|
|
1061
1064
|
},
|
|
1065
|
+
projectId: data.projectId,
|
|
1062
1066
|
});
|
|
1063
1067
|
}
|
|
1064
1068
|
}
|
|
@@ -1187,6 +1191,7 @@ export class Service extends DatabaseService<WorkspaceNotificationRule> {
|
|
|
1187
1191
|
} as WorkspacePayloadMarkdown,
|
|
1188
1192
|
],
|
|
1189
1193
|
},
|
|
1194
|
+
projectId: data.projectId,
|
|
1190
1195
|
},
|
|
1191
1196
|
);
|
|
1192
1197
|
} catch (e) {
|
|
@@ -1216,6 +1221,7 @@ export class Service extends DatabaseService<WorkspaceNotificationRule> {
|
|
|
1216
1221
|
channelNames: channelNames,
|
|
1217
1222
|
workspaceUserIds: workspaceUserIds,
|
|
1218
1223
|
},
|
|
1224
|
+
projectId: data.projectId,
|
|
1219
1225
|
});
|
|
1220
1226
|
|
|
1221
1227
|
// Log user invitations
|
|
@@ -1373,6 +1379,7 @@ export class Service extends DatabaseService<WorkspaceNotificationRule> {
|
|
|
1373
1379
|
).createChannel({
|
|
1374
1380
|
authToken: data.projectOrUserAuthTokenForWorkspace,
|
|
1375
1381
|
channelName: notificationChannel.channelName,
|
|
1382
|
+
projectId: data.projectId,
|
|
1376
1383
|
});
|
|
1377
1384
|
|
|
1378
1385
|
const notificationWorkspaceChannel: NotificationRuleWorkspaceChannel = {
|
|
@@ -225,6 +225,7 @@ export default class SlackIncidentActions {
|
|
|
225
225
|
await SlackUtil.sendMessage({
|
|
226
226
|
authToken: projectAuthToken,
|
|
227
227
|
userId: botUserId,
|
|
228
|
+
projectId: slackRequest.projectId!,
|
|
228
229
|
workspaceMessagePayload: {
|
|
229
230
|
_type: "WorkspaceMessagePayload",
|
|
230
231
|
channelIds: [slackChannelId],
|
|
@@ -280,6 +280,7 @@ export default class SlackScheduledMaintenanceActions {
|
|
|
280
280
|
await SlackUtil.sendMessage({
|
|
281
281
|
authToken: projectAuthToken,
|
|
282
282
|
userId: botUserId,
|
|
283
|
+
projectId: slackRequest.projectId!,
|
|
283
284
|
workspaceMessagePayload: {
|
|
284
285
|
_type: "WorkspaceMessagePayload",
|
|
285
286
|
channelIds: [slackChannelId],
|
|
@@ -31,6 +31,8 @@ import { DropdownOption } from "../../../../UI/Components/Dropdown/Dropdown";
|
|
|
31
31
|
import OneUptimeDate from "../../../../Types/Date";
|
|
32
32
|
import CaptureSpan from "../../Telemetry/CaptureSpan";
|
|
33
33
|
import BadDataException from "../../../../Types/Exception/BadDataException";
|
|
34
|
+
import ObjectID from "../../../../Types/ObjectID";
|
|
35
|
+
import WorkspaceProjectAuthTokenService from "../../../Services/WorkspaceProjectAuthTokenService";
|
|
34
36
|
|
|
35
37
|
export default class SlackUtil extends WorkspaceBase {
|
|
36
38
|
public static isValidSlackIncomingWebhookUrl(
|
|
@@ -181,6 +183,7 @@ export default class SlackUtil extends WorkspaceBase {
|
|
|
181
183
|
channelIds: Array<string>;
|
|
182
184
|
authToken: string;
|
|
183
185
|
sendMessageBeforeArchiving: WorkspacePayloadMarkdown;
|
|
186
|
+
projectId: ObjectID;
|
|
184
187
|
}): Promise<void> {
|
|
185
188
|
if (data.sendMessageBeforeArchiving) {
|
|
186
189
|
await this.sendMessage({
|
|
@@ -193,6 +196,7 @@ export default class SlackUtil extends WorkspaceBase {
|
|
|
193
196
|
},
|
|
194
197
|
authToken: data.authToken,
|
|
195
198
|
userId: data.userId,
|
|
199
|
+
projectId: data.projectId,
|
|
196
200
|
});
|
|
197
201
|
}
|
|
198
202
|
|
|
@@ -349,6 +353,7 @@ export default class SlackUtil extends WorkspaceBase {
|
|
|
349
353
|
authToken: string;
|
|
350
354
|
channelName: string;
|
|
351
355
|
workspaceUserId: string;
|
|
356
|
+
projectId: ObjectID;
|
|
352
357
|
}): Promise<void> {
|
|
353
358
|
if (data.channelName && data.channelName.startsWith("#")) {
|
|
354
359
|
// trim # from channel name
|
|
@@ -362,6 +367,7 @@ export default class SlackUtil extends WorkspaceBase {
|
|
|
362
367
|
await this.getWorkspaceChannelFromChannelName({
|
|
363
368
|
authToken: data.authToken,
|
|
364
369
|
channelName: data.channelName,
|
|
370
|
+
projectId: data.projectId,
|
|
365
371
|
})
|
|
366
372
|
).id;
|
|
367
373
|
|
|
@@ -376,31 +382,32 @@ export default class SlackUtil extends WorkspaceBase {
|
|
|
376
382
|
public static override async createChannelsIfDoesNotExist(data: {
|
|
377
383
|
authToken: string;
|
|
378
384
|
channelNames: Array<string>;
|
|
385
|
+
projectId: ObjectID;
|
|
379
386
|
}): Promise<Array<WorkspaceChannel>> {
|
|
380
387
|
logger.debug("Creating channels if they do not exist with data:");
|
|
381
388
|
logger.debug(data);
|
|
382
389
|
|
|
383
390
|
const workspaceChannels: Array<WorkspaceChannel> = [];
|
|
384
|
-
const existingWorkspaceChannels: Dictionary<WorkspaceChannel> =
|
|
385
|
-
await this.getAllWorkspaceChannels({
|
|
386
|
-
authToken: data.authToken,
|
|
387
|
-
});
|
|
388
391
|
|
|
389
392
|
for (let channelName of data.channelNames) {
|
|
390
|
-
//
|
|
393
|
+
// Normalize channel name
|
|
391
394
|
if (channelName && channelName.startsWith("#")) {
|
|
392
395
|
channelName = channelName.substring(1);
|
|
393
396
|
}
|
|
394
|
-
|
|
395
|
-
// convert channel name to lowercase
|
|
396
397
|
channelName = channelName.toLowerCase();
|
|
397
|
-
|
|
398
|
-
// replace spaces with hyphens
|
|
399
398
|
channelName = channelName.replace(/\s+/g, "-");
|
|
400
399
|
|
|
401
|
-
if
|
|
400
|
+
// Check if channel exists using optimized method
|
|
401
|
+
const existingChannel: WorkspaceChannel | null =
|
|
402
|
+
await this.getWorkspaceChannelByName({
|
|
403
|
+
authToken: data.authToken,
|
|
404
|
+
channelName: channelName,
|
|
405
|
+
projectId: data.projectId,
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
if (existingChannel) {
|
|
402
409
|
logger.debug(`Channel ${channelName} already exists.`);
|
|
403
|
-
workspaceChannels.push(
|
|
410
|
+
workspaceChannels.push(existingChannel);
|
|
404
411
|
continue;
|
|
405
412
|
}
|
|
406
413
|
|
|
@@ -408,6 +415,7 @@ export default class SlackUtil extends WorkspaceBase {
|
|
|
408
415
|
const channel: WorkspaceChannel = await this.createChannel({
|
|
409
416
|
authToken: data.authToken,
|
|
410
417
|
channelName: channelName,
|
|
418
|
+
projectId: data.projectId,
|
|
411
419
|
});
|
|
412
420
|
|
|
413
421
|
if (channel) {
|
|
@@ -425,26 +433,27 @@ export default class SlackUtil extends WorkspaceBase {
|
|
|
425
433
|
public static override async getWorkspaceChannelFromChannelName(data: {
|
|
426
434
|
authToken: string;
|
|
427
435
|
channelName: string;
|
|
436
|
+
projectId: ObjectID;
|
|
428
437
|
}): Promise<WorkspaceChannel> {
|
|
429
438
|
logger.debug("Getting workspace channel ID from channel name with data:");
|
|
430
439
|
logger.debug(data);
|
|
431
440
|
|
|
432
|
-
const
|
|
433
|
-
await this.
|
|
441
|
+
const channel: WorkspaceChannel | null =
|
|
442
|
+
await this.getWorkspaceChannelByName({
|
|
434
443
|
authToken: data.authToken,
|
|
444
|
+
channelName: data.channelName,
|
|
445
|
+
projectId: data.projectId,
|
|
435
446
|
});
|
|
436
447
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
if (!channels[data.channelName]) {
|
|
448
|
+
if (!channel) {
|
|
440
449
|
logger.error("Channel not found.");
|
|
441
450
|
throw new BadDataException("Channel not found.");
|
|
442
451
|
}
|
|
443
452
|
|
|
444
|
-
logger.debug("Workspace channel
|
|
445
|
-
logger.debug(
|
|
453
|
+
logger.debug("Workspace channel obtained:");
|
|
454
|
+
logger.debug(channel);
|
|
446
455
|
|
|
447
|
-
return
|
|
456
|
+
return channel;
|
|
448
457
|
}
|
|
449
458
|
|
|
450
459
|
@CaptureSpan()
|
|
@@ -584,6 +593,216 @@ export default class SlackUtil extends WorkspaceBase {
|
|
|
584
593
|
return channels;
|
|
585
594
|
}
|
|
586
595
|
|
|
596
|
+
@CaptureSpan()
|
|
597
|
+
public static async getChannelFromCache(data: {
|
|
598
|
+
projectId: ObjectID;
|
|
599
|
+
channelName: string;
|
|
600
|
+
}): Promise<WorkspaceChannel | null> {
|
|
601
|
+
logger.debug("Getting channel from cache with data:");
|
|
602
|
+
logger.debug(data);
|
|
603
|
+
|
|
604
|
+
const projectAuth: any =
|
|
605
|
+
await WorkspaceProjectAuthTokenService.getProjectAuth({
|
|
606
|
+
projectId: data.projectId,
|
|
607
|
+
workspaceType: WorkspaceType.Slack,
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
if (!projectAuth || !projectAuth.miscData) {
|
|
611
|
+
logger.debug("No project auth found or no misc data");
|
|
612
|
+
return null;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
const miscData: any = projectAuth.miscData;
|
|
616
|
+
const channelCache: any = miscData.channelCache;
|
|
617
|
+
|
|
618
|
+
if (!channelCache || !channelCache[data.channelName]) {
|
|
619
|
+
logger.debug("Channel not found in cache");
|
|
620
|
+
return null;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
const cachedChannelData: WorkspaceChannel = channelCache[
|
|
624
|
+
data.channelName
|
|
625
|
+
] as WorkspaceChannel;
|
|
626
|
+
const channel: WorkspaceChannel = {
|
|
627
|
+
id: cachedChannelData.id,
|
|
628
|
+
name: cachedChannelData.name,
|
|
629
|
+
workspaceType: WorkspaceType.Slack,
|
|
630
|
+
};
|
|
631
|
+
|
|
632
|
+
logger.debug("Channel found in cache:");
|
|
633
|
+
logger.debug(channel);
|
|
634
|
+
return channel;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
@CaptureSpan()
|
|
638
|
+
public static async updateChannelCache(data: {
|
|
639
|
+
projectId: ObjectID;
|
|
640
|
+
channelName: string;
|
|
641
|
+
channel: WorkspaceChannel;
|
|
642
|
+
}): Promise<void> {
|
|
643
|
+
logger.debug("Updating channel cache with data:");
|
|
644
|
+
logger.debug(data);
|
|
645
|
+
|
|
646
|
+
const projectAuth: any =
|
|
647
|
+
await WorkspaceProjectAuthTokenService.getProjectAuth({
|
|
648
|
+
projectId: data.projectId,
|
|
649
|
+
workspaceType: WorkspaceType.Slack,
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
if (!projectAuth) {
|
|
653
|
+
logger.debug("No project auth found, cannot update cache");
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
const miscData: any = projectAuth.miscData || {};
|
|
658
|
+
const channelCache: any = miscData.channelCache || {};
|
|
659
|
+
|
|
660
|
+
// Update the cache
|
|
661
|
+
channelCache[data.channelName] = {
|
|
662
|
+
id: data.channel.id,
|
|
663
|
+
name: data.channel.name,
|
|
664
|
+
lastUpdated: new Date().toISOString(),
|
|
665
|
+
};
|
|
666
|
+
|
|
667
|
+
// Update miscData
|
|
668
|
+
miscData.channelCache = channelCache;
|
|
669
|
+
|
|
670
|
+
// Save back to database
|
|
671
|
+
await WorkspaceProjectAuthTokenService.refreshAuthToken({
|
|
672
|
+
projectId: data.projectId,
|
|
673
|
+
workspaceType: WorkspaceType.Slack,
|
|
674
|
+
authToken: projectAuth.authToken,
|
|
675
|
+
workspaceProjectId: projectAuth.workspaceProjectId,
|
|
676
|
+
miscData: miscData,
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
logger.debug("Channel cache updated successfully");
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
@CaptureSpan()
|
|
683
|
+
public static async getWorkspaceChannelByName(data: {
|
|
684
|
+
authToken: string;
|
|
685
|
+
channelName: string;
|
|
686
|
+
projectId: ObjectID;
|
|
687
|
+
}): Promise<WorkspaceChannel | null> {
|
|
688
|
+
logger.debug("Getting workspace channel by name with data:");
|
|
689
|
+
logger.debug(data);
|
|
690
|
+
|
|
691
|
+
// Normalize channel name
|
|
692
|
+
let normalizedChannelName: string = data.channelName;
|
|
693
|
+
if (normalizedChannelName && normalizedChannelName.startsWith("#")) {
|
|
694
|
+
normalizedChannelName = normalizedChannelName.substring(1);
|
|
695
|
+
}
|
|
696
|
+
normalizedChannelName = normalizedChannelName.toLowerCase();
|
|
697
|
+
|
|
698
|
+
// Try to get from cache first
|
|
699
|
+
try {
|
|
700
|
+
const cachedChannel: WorkspaceChannel | null =
|
|
701
|
+
await this.getChannelFromCache({
|
|
702
|
+
projectId: data.projectId,
|
|
703
|
+
channelName: normalizedChannelName,
|
|
704
|
+
});
|
|
705
|
+
if (cachedChannel) {
|
|
706
|
+
logger.debug("Channel found in cache:");
|
|
707
|
+
logger.debug(cachedChannel);
|
|
708
|
+
return cachedChannel;
|
|
709
|
+
}
|
|
710
|
+
} catch (error) {
|
|
711
|
+
logger.error("Error getting channel from cache, falling back to API:");
|
|
712
|
+
logger.error(error);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
let cursor: string | undefined = undefined;
|
|
716
|
+
const maxPages: number = 10; // Limit search to prevent excessive API calls
|
|
717
|
+
let pageCount: number = 0;
|
|
718
|
+
|
|
719
|
+
do {
|
|
720
|
+
const requestBody: JSONObject = {
|
|
721
|
+
limit: 200, // Use smaller limit for faster searches
|
|
722
|
+
types: "public_channel,private_channel",
|
|
723
|
+
};
|
|
724
|
+
|
|
725
|
+
if (cursor) {
|
|
726
|
+
requestBody["cursor"] = cursor;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
const response: HTTPErrorResponse | HTTPResponse<JSONObject> =
|
|
730
|
+
await API.post<JSONObject>(
|
|
731
|
+
URL.fromString("https://slack.com/api/conversations.list"),
|
|
732
|
+
requestBody,
|
|
733
|
+
{
|
|
734
|
+
Authorization: `Bearer ${data.authToken}`,
|
|
735
|
+
["Content-Type"]: "application/x-www-form-urlencoded",
|
|
736
|
+
},
|
|
737
|
+
{
|
|
738
|
+
retries: 3,
|
|
739
|
+
exponentialBackoff: true,
|
|
740
|
+
},
|
|
741
|
+
);
|
|
742
|
+
|
|
743
|
+
if (response instanceof HTTPErrorResponse) {
|
|
744
|
+
logger.error("Error response from Slack API:");
|
|
745
|
+
logger.error(response);
|
|
746
|
+
throw response;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
// check for ok response
|
|
750
|
+
if ((response.jsonData as JSONObject)?.["ok"] !== true) {
|
|
751
|
+
logger.error("Invalid response from Slack API:");
|
|
752
|
+
logger.error(response.jsonData);
|
|
753
|
+
const messageFromSlack: string = (response.jsonData as JSONObject)?.[
|
|
754
|
+
"error"
|
|
755
|
+
] as string;
|
|
756
|
+
throw new BadRequestException("Error from Slack " + messageFromSlack);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
for (const channel of (response.jsonData as JSONObject)[
|
|
760
|
+
"channels"
|
|
761
|
+
] as Array<JSONObject>) {
|
|
762
|
+
if (!channel["id"] || !channel["name"]) {
|
|
763
|
+
continue;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
const channelName: string = (channel["name"] as string).toLowerCase();
|
|
767
|
+
if (channelName === normalizedChannelName) {
|
|
768
|
+
logger.debug("Channel found:");
|
|
769
|
+
logger.debug(channel);
|
|
770
|
+
|
|
771
|
+
const foundChannel: WorkspaceChannel = {
|
|
772
|
+
id: channel["id"] as string,
|
|
773
|
+
name: channel["name"] as string,
|
|
774
|
+
workspaceType: WorkspaceType.Slack,
|
|
775
|
+
};
|
|
776
|
+
|
|
777
|
+
// Update cache if projectId is provided
|
|
778
|
+
if (data.projectId) {
|
|
779
|
+
try {
|
|
780
|
+
await this.updateChannelCache({
|
|
781
|
+
projectId: data.projectId,
|
|
782
|
+
channelName: normalizedChannelName,
|
|
783
|
+
channel: foundChannel,
|
|
784
|
+
});
|
|
785
|
+
} catch (error) {
|
|
786
|
+
logger.error("Error updating channel cache:");
|
|
787
|
+
logger.error(error);
|
|
788
|
+
// Don't fail the request if cache update fails
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
return foundChannel;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
cursor = (
|
|
797
|
+
(response.jsonData as JSONObject)["response_metadata"] as JSONObject
|
|
798
|
+
)?.["next_cursor"] as string;
|
|
799
|
+
pageCount++;
|
|
800
|
+
} while (cursor && pageCount < maxPages);
|
|
801
|
+
|
|
802
|
+
logger.debug("Channel not found:");
|
|
803
|
+
return null;
|
|
804
|
+
}
|
|
805
|
+
|
|
587
806
|
@CaptureSpan()
|
|
588
807
|
public static override getDividerBlock(): JSONObject {
|
|
589
808
|
return {
|
|
@@ -651,6 +870,7 @@ export default class SlackUtil extends WorkspaceBase {
|
|
|
651
870
|
public static override async doesChannelExist(data: {
|
|
652
871
|
authToken: string;
|
|
653
872
|
channelName: string;
|
|
873
|
+
projectId: ObjectID;
|
|
654
874
|
}): Promise<boolean> {
|
|
655
875
|
// if channel name starts with #, remove it
|
|
656
876
|
if (data.channelName && data.channelName.startsWith("#")) {
|
|
@@ -660,18 +880,15 @@ export default class SlackUtil extends WorkspaceBase {
|
|
|
660
880
|
// convert channel name to lowercase
|
|
661
881
|
data.channelName = data.channelName.toLowerCase();
|
|
662
882
|
|
|
663
|
-
//
|
|
664
|
-
const
|
|
665
|
-
await this.
|
|
883
|
+
// Check if channel exists using optimized method
|
|
884
|
+
const channel: WorkspaceChannel | null =
|
|
885
|
+
await this.getWorkspaceChannelByName({
|
|
666
886
|
authToken: data.authToken,
|
|
887
|
+
channelName: data.channelName,
|
|
888
|
+
projectId: data.projectId,
|
|
667
889
|
});
|
|
668
890
|
|
|
669
|
-
|
|
670
|
-
if (channels[data.channelName]) {
|
|
671
|
-
return true;
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
return false;
|
|
891
|
+
return channel !== null;
|
|
675
892
|
}
|
|
676
893
|
|
|
677
894
|
@CaptureSpan()
|
|
@@ -679,6 +896,7 @@ export default class SlackUtil extends WorkspaceBase {
|
|
|
679
896
|
workspaceMessagePayload: WorkspaceMessagePayload;
|
|
680
897
|
authToken: string; // which auth token should we use to send.
|
|
681
898
|
userId: string;
|
|
899
|
+
projectId: ObjectID;
|
|
682
900
|
}): Promise<WorkspaceSendMessageResponse> {
|
|
683
901
|
logger.debug("Sending message to Slack with data:");
|
|
684
902
|
logger.debug(data);
|
|
@@ -690,24 +908,21 @@ export default class SlackUtil extends WorkspaceBase {
|
|
|
690
908
|
logger.debug("Blocks generated from workspace message payload:");
|
|
691
909
|
logger.debug(blocks);
|
|
692
910
|
|
|
693
|
-
const existingWorkspaceChannels: Dictionary<WorkspaceChannel> =
|
|
694
|
-
await this.getAllWorkspaceChannels({
|
|
695
|
-
authToken: data.authToken,
|
|
696
|
-
});
|
|
697
|
-
|
|
698
911
|
const workspaceChannelsToPostTo: Array<WorkspaceChannel> = [];
|
|
699
912
|
|
|
913
|
+
// Resolve channel names efficiently
|
|
700
914
|
for (let channelName of data.workspaceMessagePayload.channelNames) {
|
|
701
915
|
if (channelName && channelName.startsWith("#")) {
|
|
702
916
|
// trim # from channel name
|
|
703
917
|
channelName = channelName.substring(1);
|
|
704
918
|
}
|
|
705
919
|
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
920
|
+
const channel: WorkspaceChannel | null =
|
|
921
|
+
await this.getWorkspaceChannelByName({
|
|
922
|
+
authToken: data.authToken,
|
|
923
|
+
channelName: channelName,
|
|
924
|
+
projectId: data.projectId,
|
|
925
|
+
});
|
|
711
926
|
|
|
712
927
|
if (channel) {
|
|
713
928
|
workspaceChannelsToPostTo.push(channel);
|
|
@@ -868,6 +1083,7 @@ export default class SlackUtil extends WorkspaceBase {
|
|
|
868
1083
|
public static override async createChannel(data: {
|
|
869
1084
|
authToken: string;
|
|
870
1085
|
channelName: string;
|
|
1086
|
+
projectId: ObjectID;
|
|
871
1087
|
}): Promise<WorkspaceChannel> {
|
|
872
1088
|
if (data.channelName && data.channelName.startsWith("#")) {
|
|
873
1089
|
data.channelName = data.channelName.substring(1);
|
|
@@ -935,6 +1151,20 @@ export default class SlackUtil extends WorkspaceBase {
|
|
|
935
1151
|
|
|
936
1152
|
logger.debug("Channel created successfully:");
|
|
937
1153
|
logger.debug(channel);
|
|
1154
|
+
|
|
1155
|
+
// Cache the created channel
|
|
1156
|
+
try {
|
|
1157
|
+
await this.updateChannelCache({
|
|
1158
|
+
projectId: data.projectId,
|
|
1159
|
+
channelName: data.channelName,
|
|
1160
|
+
channel: channel,
|
|
1161
|
+
});
|
|
1162
|
+
} catch (error) {
|
|
1163
|
+
logger.error("Error caching created channel:");
|
|
1164
|
+
logger.error(error);
|
|
1165
|
+
// Don't fail the creation if caching fails
|
|
1166
|
+
}
|
|
1167
|
+
|
|
938
1168
|
return channel;
|
|
939
1169
|
}
|
|
940
1170
|
|
|
@@ -194,6 +194,7 @@ export default class WorkspaceUtil {
|
|
|
194
194
|
await WorkspaceUtil.getWorkspaceTypeUtil(workspaceType).sendMessage({
|
|
195
195
|
userId: botUserId,
|
|
196
196
|
authToken: projectAuthToken.authToken,
|
|
197
|
+
projectId: data.projectId,
|
|
197
198
|
workspaceMessagePayload: messagePayloadByWorkspace,
|
|
198
199
|
});
|
|
199
200
|
|
|
@@ -213,6 +214,7 @@ export default class WorkspaceUtil {
|
|
|
213
214
|
projectOrUserAuthTokenForWorkspace: string;
|
|
214
215
|
workspaceType: WorkspaceType;
|
|
215
216
|
workspaceMessagePayload: WorkspaceMessagePayload;
|
|
217
|
+
projectId: ObjectID;
|
|
216
218
|
}): Promise<WorkspaceSendMessageResponse> {
|
|
217
219
|
logger.debug("postToWorkspaceChannels called with data:");
|
|
218
220
|
logger.debug(data);
|
|
@@ -222,6 +224,7 @@ export default class WorkspaceUtil {
|
|
|
222
224
|
userId: data.workspaceUserId,
|
|
223
225
|
workspaceMessagePayload: data.workspaceMessagePayload,
|
|
224
226
|
authToken: data.projectOrUserAuthTokenForWorkspace,
|
|
227
|
+
projectId: data.projectId,
|
|
225
228
|
});
|
|
226
229
|
|
|
227
230
|
logger.debug("Message posted to workspace channels successfully");
|
|
@@ -3,6 +3,7 @@ import HTTPResponse from "../../../Types/API/HTTPResponse";
|
|
|
3
3
|
import Dictionary from "../../../Types/Dictionary";
|
|
4
4
|
import NotImplementedException from "../../../Types/Exception/NotImplementedException";
|
|
5
5
|
import { JSONObject } from "../../../Types/JSON";
|
|
6
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
6
7
|
import WorkspaceChannelInvitationPayload from "../../../Types/Workspace/WorkspaceChannelInvitationPayload";
|
|
7
8
|
import WorkspaceMessagePayload, {
|
|
8
9
|
WorkspaceCheckboxBlock,
|
|
@@ -53,6 +54,7 @@ export default class WorkspaceBase {
|
|
|
53
54
|
public static async doesChannelExist(_data: {
|
|
54
55
|
authToken: string;
|
|
55
56
|
channelName: string;
|
|
57
|
+
projectId: ObjectID;
|
|
56
58
|
}): Promise<boolean> {
|
|
57
59
|
throw new NotImplementedException();
|
|
58
60
|
}
|
|
@@ -63,6 +65,7 @@ export default class WorkspaceBase {
|
|
|
63
65
|
authToken: string;
|
|
64
66
|
userId: string;
|
|
65
67
|
sendMessageBeforeArchiving: WorkspacePayloadMarkdown;
|
|
68
|
+
projectId: ObjectID;
|
|
66
69
|
}): Promise<void> {
|
|
67
70
|
throw new NotImplementedException();
|
|
68
71
|
}
|
|
@@ -121,6 +124,7 @@ export default class WorkspaceBase {
|
|
|
121
124
|
public static async inviteUsersToChannels(data: {
|
|
122
125
|
authToken: string;
|
|
123
126
|
workspaceChannelInvitationPayload: WorkspaceChannelInvitationPayload;
|
|
127
|
+
projectId: ObjectID;
|
|
124
128
|
}): Promise<void> {
|
|
125
129
|
for (const channelName of data.workspaceChannelInvitationPayload
|
|
126
130
|
.channelNames) {
|
|
@@ -129,6 +133,7 @@ export default class WorkspaceBase {
|
|
|
129
133
|
channelName: channelName,
|
|
130
134
|
workspaceUserIds:
|
|
131
135
|
data.workspaceChannelInvitationPayload.workspaceUserIds,
|
|
136
|
+
projectId: data.projectId,
|
|
132
137
|
});
|
|
133
138
|
}
|
|
134
139
|
}
|
|
@@ -138,12 +143,14 @@ export default class WorkspaceBase {
|
|
|
138
143
|
authToken: string;
|
|
139
144
|
channelName: string;
|
|
140
145
|
workspaceUserIds: Array<string>;
|
|
146
|
+
projectId: ObjectID;
|
|
141
147
|
}): Promise<void> {
|
|
142
148
|
for (const userId of data.workspaceUserIds) {
|
|
143
149
|
await this.inviteUserToChannelByChannelName({
|
|
144
150
|
authToken: data.authToken,
|
|
145
151
|
channelName: data.channelName,
|
|
146
152
|
workspaceUserId: userId,
|
|
153
|
+
projectId: data.projectId,
|
|
147
154
|
});
|
|
148
155
|
}
|
|
149
156
|
}
|
|
@@ -153,6 +160,7 @@ export default class WorkspaceBase {
|
|
|
153
160
|
authToken: string;
|
|
154
161
|
channelName: string;
|
|
155
162
|
workspaceUserId: string;
|
|
163
|
+
projectId: ObjectID;
|
|
156
164
|
}): Promise<void> {
|
|
157
165
|
throw new NotImplementedException();
|
|
158
166
|
}
|
|
@@ -175,6 +183,7 @@ export default class WorkspaceBase {
|
|
|
175
183
|
public static async createChannelsIfDoesNotExist(_data: {
|
|
176
184
|
authToken: string;
|
|
177
185
|
channelNames: Array<string>;
|
|
186
|
+
projectId: ObjectID;
|
|
178
187
|
}): Promise<Array<WorkspaceChannel>> {
|
|
179
188
|
throw new NotImplementedException();
|
|
180
189
|
}
|
|
@@ -192,6 +201,7 @@ export default class WorkspaceBase {
|
|
|
192
201
|
workspaceMessagePayload: WorkspaceMessagePayload;
|
|
193
202
|
authToken: string; // which auth token should we use to send.
|
|
194
203
|
userId: string;
|
|
204
|
+
projectId: ObjectID;
|
|
195
205
|
}): Promise<WorkspaceSendMessageResponse> {
|
|
196
206
|
throw new NotImplementedException();
|
|
197
207
|
}
|
|
@@ -207,6 +217,7 @@ export default class WorkspaceBase {
|
|
|
207
217
|
public static async getWorkspaceChannelFromChannelName(_data: {
|
|
208
218
|
authToken: string;
|
|
209
219
|
channelName: string;
|
|
220
|
+
projectId: ObjectID;
|
|
210
221
|
}): Promise<WorkspaceChannel> {
|
|
211
222
|
throw new NotImplementedException();
|
|
212
223
|
}
|
|
@@ -215,6 +226,7 @@ export default class WorkspaceBase {
|
|
|
215
226
|
public static async createChannel(_data: {
|
|
216
227
|
authToken: string;
|
|
217
228
|
channelName: string;
|
|
229
|
+
projectId: ObjectID;
|
|
218
230
|
}): Promise<WorkspaceChannel> {
|
|
219
231
|
throw new NotImplementedException();
|
|
220
232
|
}
|