@urugus/slack-cli 0.2.3 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/utils/format-utils.d.ts.map +1 -1
- package/dist/utils/format-utils.js +2 -1
- package/dist/utils/format-utils.js.map +1 -1
- package/dist/utils/mention-utils.d.ts +17 -0
- package/dist/utils/mention-utils.d.ts.map +1 -0
- package/dist/utils/mention-utils.js +45 -0
- package/dist/utils/mention-utils.js.map +1 -0
- package/dist/utils/slack-operations/message-operations.d.ts.map +1 -1
- package/dist/utils/slack-operations/message-operations.js +3 -2
- package/dist/utils/slack-operations/message-operations.js.map +1 -1
- package/dist/utils/slack-patterns.d.ts +6 -0
- package/dist/utils/slack-patterns.d.ts.map +1 -0
- package/dist/utils/slack-patterns.js +11 -0
- package/dist/utils/slack-patterns.js.map +1 -0
- package/package.json +1 -1
- package/src/utils/format-utils.ts +3 -1
- package/src/utils/mention-utils.ts +47 -0
- package/src/utils/slack-operations/message-operations.ts +3 -2
- package/src/utils/slack-patterns.ts +9 -0
- package/tests/utils/mention-utils.test.ts +100 -0
- package/tests/utils/slack-operations/message-operations.test.ts +126 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format-utils.d.ts","sourceRoot":"","sources":["../../src/utils/format-utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"format-utils.d.ts","sourceRoot":"","sources":["../../src/utils/format-utils.ts"],"names":[],"mappings":"AAEA,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAM7F"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.formatMessageWithMentions = formatMessageWithMentions;
|
|
4
|
+
const slack_patterns_1 = require("./slack-patterns");
|
|
4
5
|
function formatMessageWithMentions(message, users) {
|
|
5
6
|
// Replace <@USERID> mentions with @username
|
|
6
|
-
return message.replace(
|
|
7
|
+
return message.replace(slack_patterns_1.USER_MENTION_PATTERN, (match, userId) => {
|
|
7
8
|
const username = users.get(userId) || userId;
|
|
8
9
|
return `@${username}`;
|
|
9
10
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format-utils.js","sourceRoot":"","sources":["../../src/utils/format-utils.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"format-utils.js","sourceRoot":"","sources":["../../src/utils/format-utils.ts"],"names":[],"mappings":";;AAEA,8DAMC;AARD,qDAAwD;AAExD,SAAgB,yBAAyB,CAAC,OAAe,EAAE,KAA0B;IACnF,4CAA4C;IAC5C,OAAO,OAAO,CAAC,OAAO,CAAC,qCAAoB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;QAC7D,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC;QAC7C,OAAO,IAAI,QAAQ,EAAE,CAAC;IACxB,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts all user IDs from mentions in a text
|
|
3
|
+
* @param text - The text containing Slack mentions
|
|
4
|
+
* @returns Array of unique user IDs found in mentions
|
|
5
|
+
*/
|
|
6
|
+
export declare function extractUserIdsFromMentions(text: string): string[];
|
|
7
|
+
/**
|
|
8
|
+
* Extracts all unique user IDs from an array of messages
|
|
9
|
+
* Includes both message authors and mentioned users
|
|
10
|
+
* @param messages - Array of messages to extract user IDs from
|
|
11
|
+
* @returns Array of unique user IDs
|
|
12
|
+
*/
|
|
13
|
+
export declare function extractAllUserIds(messages: Array<{
|
|
14
|
+
user?: string;
|
|
15
|
+
text?: string;
|
|
16
|
+
}>): string[];
|
|
17
|
+
//# sourceMappingURL=mention-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mention-utils.d.ts","sourceRoot":"","sources":["../../src/utils/mention-utils.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAYjE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,MAAM,EAAE,CAmB7F"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractUserIdsFromMentions = extractUserIdsFromMentions;
|
|
4
|
+
exports.extractAllUserIds = extractAllUserIds;
|
|
5
|
+
const slack_patterns_1 = require("./slack-patterns");
|
|
6
|
+
/**
|
|
7
|
+
* Extracts all user IDs from mentions in a text
|
|
8
|
+
* @param text - The text containing Slack mentions
|
|
9
|
+
* @returns Array of unique user IDs found in mentions
|
|
10
|
+
*/
|
|
11
|
+
function extractUserIdsFromMentions(text) {
|
|
12
|
+
const userIds = [];
|
|
13
|
+
const matches = text.matchAll(slack_patterns_1.USER_MENTION_PATTERN);
|
|
14
|
+
for (const match of matches) {
|
|
15
|
+
const userId = match[1];
|
|
16
|
+
if (userId) {
|
|
17
|
+
userIds.push(userId);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return userIds;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Extracts all unique user IDs from an array of messages
|
|
24
|
+
* Includes both message authors and mentioned users
|
|
25
|
+
* @param messages - Array of messages to extract user IDs from
|
|
26
|
+
* @returns Array of unique user IDs
|
|
27
|
+
*/
|
|
28
|
+
function extractAllUserIds(messages) {
|
|
29
|
+
const userIds = new Set();
|
|
30
|
+
for (const message of messages) {
|
|
31
|
+
// Add message author
|
|
32
|
+
if (message.user) {
|
|
33
|
+
userIds.add(message.user);
|
|
34
|
+
}
|
|
35
|
+
// Add mentioned users
|
|
36
|
+
if (message.text) {
|
|
37
|
+
const mentionedIds = extractUserIdsFromMentions(message.text);
|
|
38
|
+
for (const id of mentionedIds) {
|
|
39
|
+
userIds.add(id);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return Array.from(userIds);
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=mention-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mention-utils.js","sourceRoot":"","sources":["../../src/utils/mention-utils.ts"],"names":[],"mappings":";;AAOA,gEAYC;AAQD,8CAmBC;AA9CD,qDAAwD;AAExD;;;;GAIG;AACH,SAAgB,0BAA0B,CAAC,IAAY;IACrD,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,qCAAoB,CAAC,CAAC;IAEpD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACxB,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AACH,SAAgB,iBAAiB,CAAC,QAAiD;IACjF,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAElC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,qBAAqB;QACrB,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;QAED,sBAAsB;QACtB,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,MAAM,YAAY,GAAG,0BAA0B,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAC9D,KAAK,MAAM,EAAE,IAAI,YAAY,EAAE,CAAC;gBAC9B,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AAC7B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-operations.d.ts","sourceRoot":"","sources":["../../../src/utils/slack-operations/message-operations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGhD,OAAO,EAAW,cAAc,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"message-operations.d.ts","sourceRoot":"","sources":["../../../src/utils/slack-operations/message-operations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGhD,OAAO,EAAW,cAAc,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAIlG,qBAAa,iBAAkB,SAAQ,eAAe;IACpD,OAAO,CAAC,UAAU,CAAoB;gBAE1B,KAAK,EAAE,MAAM;IAKnB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAO5E,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAyB5E,gBAAgB,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;YAsC/D,aAAa;CAmB5B"}
|
|
@@ -5,6 +5,7 @@ const base_client_1 = require("./base-client");
|
|
|
5
5
|
const channel_resolver_1 = require("../channel-resolver");
|
|
6
6
|
const constants_1 = require("../constants");
|
|
7
7
|
const channel_operations_1 = require("./channel-operations");
|
|
8
|
+
const mention_utils_1 = require("../mention-utils");
|
|
8
9
|
class MessageOperations extends base_client_1.BaseSlackClient {
|
|
9
10
|
constructor(token) {
|
|
10
11
|
super(token);
|
|
@@ -29,8 +30,8 @@ class MessageOperations extends base_client_1.BaseSlackClient {
|
|
|
29
30
|
oldest: options.oldest,
|
|
30
31
|
});
|
|
31
32
|
const messages = response.messages;
|
|
32
|
-
//
|
|
33
|
-
const userIds =
|
|
33
|
+
// Extract all unique user IDs (authors and mentioned users)
|
|
34
|
+
const userIds = (0, mention_utils_1.extractAllUserIds)(messages);
|
|
34
35
|
const users = await this.fetchUserInfo(userIds);
|
|
35
36
|
return { messages, users };
|
|
36
37
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-operations.js","sourceRoot":"","sources":["../../../src/utils/slack-operations/message-operations.ts"],"names":[],"mappings":";;;AACA,+CAAgD;AAChD,0DAAsD;AACtD,4CAAwC;AAExC,6DAAyD;
|
|
1
|
+
{"version":3,"file":"message-operations.js","sourceRoot":"","sources":["../../../src/utils/slack-operations/message-operations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slack-patterns.d.ts","sourceRoot":"","sources":["../../src/utils/slack-patterns.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,eAAO,MAAM,oBAAoB,QAAoB,CAAC;AAGtD,eAAO,MAAM,2BAA2B,QAAmB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Common regex patterns for Slack message parsing
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SINGLE_USER_MENTION_PATTERN = exports.USER_MENTION_PATTERN = void 0;
|
|
7
|
+
// Matches Slack user mentions in the format <@USERID>
|
|
8
|
+
exports.USER_MENTION_PATTERN = /<@([A-Z0-9]+)>/g;
|
|
9
|
+
// Matches a single user mention (non-global)
|
|
10
|
+
exports.SINGLE_USER_MENTION_PATTERN = /<@([A-Z0-9]+)>/;
|
|
11
|
+
//# sourceMappingURL=slack-patterns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slack-patterns.js","sourceRoot":"","sources":["../../src/utils/slack-patterns.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,sDAAsD;AACzC,QAAA,oBAAoB,GAAG,iBAAiB,CAAC;AAEtD,6CAA6C;AAChC,QAAA,2BAA2B,GAAG,gBAAgB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { USER_MENTION_PATTERN } from './slack-patterns';
|
|
2
|
+
|
|
1
3
|
export function formatMessageWithMentions(message: string, users: Map<string, string>): string {
|
|
2
4
|
// Replace <@USERID> mentions with @username
|
|
3
|
-
return message.replace(
|
|
5
|
+
return message.replace(USER_MENTION_PATTERN, (match, userId) => {
|
|
4
6
|
const username = users.get(userId) || userId;
|
|
5
7
|
return `@${username}`;
|
|
6
8
|
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { USER_MENTION_PATTERN } from './slack-patterns';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Extracts all user IDs from mentions in a text
|
|
5
|
+
* @param text - The text containing Slack mentions
|
|
6
|
+
* @returns Array of unique user IDs found in mentions
|
|
7
|
+
*/
|
|
8
|
+
export function extractUserIdsFromMentions(text: string): string[] {
|
|
9
|
+
const userIds: string[] = [];
|
|
10
|
+
const matches = text.matchAll(USER_MENTION_PATTERN);
|
|
11
|
+
|
|
12
|
+
for (const match of matches) {
|
|
13
|
+
const userId = match[1];
|
|
14
|
+
if (userId) {
|
|
15
|
+
userIds.push(userId);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return userIds;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Extracts all unique user IDs from an array of messages
|
|
24
|
+
* Includes both message authors and mentioned users
|
|
25
|
+
* @param messages - Array of messages to extract user IDs from
|
|
26
|
+
* @returns Array of unique user IDs
|
|
27
|
+
*/
|
|
28
|
+
export function extractAllUserIds(messages: Array<{ user?: string; text?: string }>): string[] {
|
|
29
|
+
const userIds = new Set<string>();
|
|
30
|
+
|
|
31
|
+
for (const message of messages) {
|
|
32
|
+
// Add message author
|
|
33
|
+
if (message.user) {
|
|
34
|
+
userIds.add(message.user);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Add mentioned users
|
|
38
|
+
if (message.text) {
|
|
39
|
+
const mentionedIds = extractUserIdsFromMentions(message.text);
|
|
40
|
+
for (const id of mentionedIds) {
|
|
41
|
+
userIds.add(id);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return Array.from(userIds);
|
|
47
|
+
}
|
|
@@ -4,6 +4,7 @@ import { channelResolver } from '../channel-resolver';
|
|
|
4
4
|
import { DEFAULTS } from '../constants';
|
|
5
5
|
import { Message, HistoryOptions, HistoryResult, ChannelUnreadResult } from '../slack-api-client';
|
|
6
6
|
import { ChannelOperations } from './channel-operations';
|
|
7
|
+
import { extractAllUserIds } from '../mention-utils';
|
|
7
8
|
|
|
8
9
|
export class MessageOperations extends BaseSlackClient {
|
|
9
10
|
private channelOps: ChannelOperations;
|
|
@@ -38,8 +39,8 @@ export class MessageOperations extends BaseSlackClient {
|
|
|
38
39
|
|
|
39
40
|
const messages = response.messages as Message[];
|
|
40
41
|
|
|
41
|
-
//
|
|
42
|
-
const userIds =
|
|
42
|
+
// Extract all unique user IDs (authors and mentioned users)
|
|
43
|
+
const userIds = extractAllUserIds(messages);
|
|
43
44
|
const users = await this.fetchUserInfo(userIds);
|
|
44
45
|
|
|
45
46
|
return { messages, users };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Common regex patterns for Slack message parsing
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Matches Slack user mentions in the format <@USERID>
|
|
6
|
+
export const USER_MENTION_PATTERN = /<@([A-Z0-9]+)>/g;
|
|
7
|
+
|
|
8
|
+
// Matches a single user mention (non-global)
|
|
9
|
+
export const SINGLE_USER_MENTION_PATTERN = /<@([A-Z0-9]+)>/;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { extractUserIdsFromMentions, extractAllUserIds } from '../../src/utils/mention-utils';
|
|
3
|
+
|
|
4
|
+
describe('mention-utils', () => {
|
|
5
|
+
describe('extractUserIdsFromMentions', () => {
|
|
6
|
+
it('should extract single user ID from mention', () => {
|
|
7
|
+
const text = 'Hello <@U123456789>';
|
|
8
|
+
const userIds = extractUserIdsFromMentions(text);
|
|
9
|
+
expect(userIds).toEqual(['U123456789']);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('should extract multiple user IDs from mentions', () => {
|
|
13
|
+
const text = 'Hey <@U123456789> and <@U987654321>, please check this';
|
|
14
|
+
const userIds = extractUserIdsFromMentions(text);
|
|
15
|
+
expect(userIds).toEqual(['U123456789', 'U987654321']);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should handle duplicate mentions', () => {
|
|
19
|
+
const text = '<@U123456789> mentioned <@U123456789> again';
|
|
20
|
+
const userIds = extractUserIdsFromMentions(text);
|
|
21
|
+
expect(userIds).toEqual(['U123456789', 'U123456789']);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should return empty array for text without mentions', () => {
|
|
25
|
+
const text = 'No mentions here';
|
|
26
|
+
const userIds = extractUserIdsFromMentions(text);
|
|
27
|
+
expect(userIds).toEqual([]);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should handle empty text', () => {
|
|
31
|
+
const userIds = extractUserIdsFromMentions('');
|
|
32
|
+
expect(userIds).toEqual([]);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should ignore malformed mentions', () => {
|
|
36
|
+
const text = 'Invalid <@> mention and <@lowercase> mention';
|
|
37
|
+
const userIds = extractUserIdsFromMentions(text);
|
|
38
|
+
expect(userIds).toEqual([]);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe('extractAllUserIds', () => {
|
|
43
|
+
it('should extract user IDs from message authors only', () => {
|
|
44
|
+
const messages = [
|
|
45
|
+
{ user: 'U111111111', text: 'Hello world' },
|
|
46
|
+
{ user: 'U222222222', text: 'Hi there' },
|
|
47
|
+
];
|
|
48
|
+
const userIds = extractAllUserIds(messages);
|
|
49
|
+
expect(userIds).toEqual(['U111111111', 'U222222222']);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should extract user IDs from mentions only', () => {
|
|
53
|
+
const messages = [
|
|
54
|
+
{ text: 'Hello <@U333333333>' },
|
|
55
|
+
{ text: 'Hi <@U444444444>' },
|
|
56
|
+
];
|
|
57
|
+
const userIds = extractAllUserIds(messages);
|
|
58
|
+
expect(userIds).toEqual(['U333333333', 'U444444444']);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should extract both authors and mentioned users', () => {
|
|
62
|
+
const messages = [
|
|
63
|
+
{ user: 'U111111111', text: 'Hello <@U222222222>' },
|
|
64
|
+
{ user: 'U333333333', text: 'Hi <@U444444444> and <@U555555555>' },
|
|
65
|
+
];
|
|
66
|
+
const userIds = extractAllUserIds(messages);
|
|
67
|
+
expect(userIds.sort()).toEqual([
|
|
68
|
+
'U111111111',
|
|
69
|
+
'U222222222',
|
|
70
|
+
'U333333333',
|
|
71
|
+
'U444444444',
|
|
72
|
+
'U555555555',
|
|
73
|
+
]);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should remove duplicate user IDs', () => {
|
|
77
|
+
const messages = [
|
|
78
|
+
{ user: 'U111111111', text: 'Hello <@U111111111>' },
|
|
79
|
+
{ user: 'U111111111', text: 'Another message' },
|
|
80
|
+
];
|
|
81
|
+
const userIds = extractAllUserIds(messages);
|
|
82
|
+
expect(userIds).toEqual(['U111111111']);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should handle messages without user or text', () => {
|
|
86
|
+
const messages = [
|
|
87
|
+
{ user: 'U111111111' },
|
|
88
|
+
{ text: 'No user here' },
|
|
89
|
+
{},
|
|
90
|
+
];
|
|
91
|
+
const userIds = extractAllUserIds(messages);
|
|
92
|
+
expect(userIds).toEqual(['U111111111']);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('should handle empty messages array', () => {
|
|
96
|
+
const userIds = extractAllUserIds([]);
|
|
97
|
+
expect(userIds).toEqual([]);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
});
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { beforeEach, describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { MessageOperations } from '../../../src/utils/slack-operations/message-operations';
|
|
3
|
+
import { channelResolver } from '../../../src/utils/channel-resolver';
|
|
4
|
+
|
|
5
|
+
vi.mock('@slack/web-api', () => ({
|
|
6
|
+
WebClient: vi.fn().mockImplementation(() => ({
|
|
7
|
+
conversations: {
|
|
8
|
+
history: vi.fn(),
|
|
9
|
+
},
|
|
10
|
+
users: {
|
|
11
|
+
info: vi.fn(),
|
|
12
|
+
},
|
|
13
|
+
chat: {
|
|
14
|
+
postMessage: vi.fn(),
|
|
15
|
+
},
|
|
16
|
+
})),
|
|
17
|
+
LogLevel: {
|
|
18
|
+
ERROR: 'error',
|
|
19
|
+
},
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
vi.mock('../../../src/utils/channel-resolver');
|
|
23
|
+
|
|
24
|
+
describe('MessageOperations', () => {
|
|
25
|
+
let messageOps: MessageOperations;
|
|
26
|
+
let mockClient: any;
|
|
27
|
+
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
vi.clearAllMocks();
|
|
30
|
+
messageOps = new MessageOperations('test-token');
|
|
31
|
+
mockClient = (messageOps as any).client;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe('getHistory with mentions', () => {
|
|
35
|
+
it('should fetch user info for mentioned users in message text', async () => {
|
|
36
|
+
const mockMessages = [
|
|
37
|
+
{
|
|
38
|
+
type: 'message',
|
|
39
|
+
text: 'Hello <@U123456789> can you check this?',
|
|
40
|
+
user: 'U987654321',
|
|
41
|
+
ts: '1234567890.123456',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
type: 'message',
|
|
45
|
+
text: '<@U111111111> and <@U222222222> please review',
|
|
46
|
+
user: 'U333333333',
|
|
47
|
+
ts: '1234567891.123456',
|
|
48
|
+
},
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
const mockUsersInfo = {
|
|
52
|
+
U123456789: { ok: true, user: { name: 'john.doe' } },
|
|
53
|
+
U987654321: { ok: true, user: { name: 'jane.smith' } },
|
|
54
|
+
U111111111: { ok: true, user: { name: 'alice.brown' } },
|
|
55
|
+
U222222222: { ok: true, user: { name: 'bob.wilson' } },
|
|
56
|
+
U333333333: { ok: true, user: { name: 'charlie.davis' } },
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
mockClient.conversations.history.mockResolvedValue({
|
|
60
|
+
ok: true,
|
|
61
|
+
messages: mockMessages,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
mockClient.users.info.mockImplementation(({ user }: { user: string }) => {
|
|
65
|
+
return Promise.resolve(mockUsersInfo[user] || { ok: false });
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
vi.mocked(channelResolver.resolveChannelId).mockResolvedValue('C123456789');
|
|
69
|
+
|
|
70
|
+
const result = await messageOps.getHistory('test-channel', { limit: 10 });
|
|
71
|
+
|
|
72
|
+
// Verify all user IDs were fetched (both message authors and mentioned users)
|
|
73
|
+
expect(mockClient.users.info).toHaveBeenCalledTimes(5);
|
|
74
|
+
expect(mockClient.users.info).toHaveBeenCalledWith({ user: 'U987654321' });
|
|
75
|
+
expect(mockClient.users.info).toHaveBeenCalledWith({ user: 'U333333333' });
|
|
76
|
+
expect(mockClient.users.info).toHaveBeenCalledWith({ user: 'U123456789' });
|
|
77
|
+
expect(mockClient.users.info).toHaveBeenCalledWith({ user: 'U111111111' });
|
|
78
|
+
expect(mockClient.users.info).toHaveBeenCalledWith({ user: 'U222222222' });
|
|
79
|
+
|
|
80
|
+
// Verify the returned users map contains all users
|
|
81
|
+
expect(result.users.get('U123456789')).toBe('john.doe');
|
|
82
|
+
expect(result.users.get('U987654321')).toBe('jane.smith');
|
|
83
|
+
expect(result.users.get('U111111111')).toBe('alice.brown');
|
|
84
|
+
expect(result.users.get('U222222222')).toBe('bob.wilson');
|
|
85
|
+
expect(result.users.get('U333333333')).toBe('charlie.davis');
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should handle messages with own mentions correctly', async () => {
|
|
89
|
+
const mockMessages = [
|
|
90
|
+
{
|
|
91
|
+
type: 'message',
|
|
92
|
+
text: '<@U07L5D50RAL> please check this task',
|
|
93
|
+
user: 'U123456789',
|
|
94
|
+
ts: '1234567890.123456',
|
|
95
|
+
},
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
const mockUsersInfo = {
|
|
99
|
+
U123456789: { ok: true, user: { name: 'john.doe' } },
|
|
100
|
+
U07L5D50RAL: { ok: true, user: { name: 'koguchi_s' } },
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
mockClient.conversations.history.mockResolvedValue({
|
|
104
|
+
ok: true,
|
|
105
|
+
messages: mockMessages,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
mockClient.users.info.mockImplementation(({ user }: { user: string }) => {
|
|
109
|
+
return Promise.resolve(mockUsersInfo[user] || { ok: false });
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
vi.mocked(channelResolver.resolveChannelId).mockResolvedValue('C123456789');
|
|
113
|
+
|
|
114
|
+
const result = await messageOps.getHistory('test-channel', { limit: 10 });
|
|
115
|
+
|
|
116
|
+
// Verify both users were fetched
|
|
117
|
+
expect(mockClient.users.info).toHaveBeenCalledTimes(2);
|
|
118
|
+
expect(mockClient.users.info).toHaveBeenCalledWith({ user: 'U123456789' });
|
|
119
|
+
expect(mockClient.users.info).toHaveBeenCalledWith({ user: 'U07L5D50RAL' });
|
|
120
|
+
|
|
121
|
+
// Verify the returned users map contains both users
|
|
122
|
+
expect(result.users.get('U123456789')).toBe('john.doe');
|
|
123
|
+
expect(result.users.get('U07L5D50RAL')).toBe('koguchi_s');
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
});
|