@jiexiaoyin/wecom-api 0.0.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.
Files changed (58) hide show
  1. package/README.md +228 -0
  2. package/config.example.json +7 -0
  3. package/config.js +76 -0
  4. package/docs/approval-templates.example.json +11 -0
  5. package/docs/nginx-mirror.md +193 -0
  6. package/openclaw.plugin.json +15 -0
  7. package/package.json +34 -0
  8. package/plugin.cjs +172 -0
  9. package/plugin.ts +136 -0
  10. package/skills/wecom-api/SKILL.md +40 -0
  11. package/skills/wecom-api/index.js +288 -0
  12. package/skills/wecom-api/openclaw.plugin.json +10 -0
  13. package/src/callback-helper.js +198 -0
  14. package/src/config.cjs +286 -0
  15. package/src/core/permission.js +479 -0
  16. package/src/crypto.js +130 -0
  17. package/src/index.js +199 -0
  18. package/src/modules/addressbook/index.js +413 -0
  19. package/src/modules/addressbook_cache/index.js +365 -0
  20. package/src/modules/advanced/index.js +159 -0
  21. package/src/modules/app/index.js +102 -0
  22. package/src/modules/approval/index.js +146 -0
  23. package/src/modules/auth/index.js +103 -0
  24. package/src/modules/callback/index.js +1180 -0
  25. package/src/modules/chain/index.js +193 -0
  26. package/src/modules/checkin/index.js +142 -0
  27. package/src/modules/checkin_rules/index.js +251 -0
  28. package/src/modules/contact/index.js +481 -0
  29. package/src/modules/contact_stats/index.js +349 -0
  30. package/src/modules/custom/index.js +140 -0
  31. package/src/modules/customer/index.js +51 -0
  32. package/src/modules/disk/index.js +245 -0
  33. package/src/modules/document/index.js +282 -0
  34. package/src/modules/hr/index.js +93 -0
  35. package/src/modules/intelligence/index.js +346 -0
  36. package/src/modules/kf/index.js +74 -0
  37. package/src/modules/live/index.js +122 -0
  38. package/src/modules/media/index.js +183 -0
  39. package/src/modules/meeting/index.js +665 -0
  40. package/src/modules/message/index.js +402 -0
  41. package/src/modules/messenger/index.js +208 -0
  42. package/src/modules/moments/index.js +161 -0
  43. package/src/modules/msgaudit/index.js +24 -0
  44. package/src/modules/notify/index.js +81 -0
  45. package/src/modules/oceanengine/index.js +199 -0
  46. package/src/modules/openchat/index.js +197 -0
  47. package/src/modules/phone/index.js +45 -0
  48. package/src/modules/room/index.js +178 -0
  49. package/src/modules/schedule/index.js +246 -0
  50. package/src/modules/school/index.js +199 -0
  51. package/src/modules/security/index.js +223 -0
  52. package/src/modules/sensitive/index.js +170 -0
  53. package/src/modules/thirdparty/index.js +145 -0
  54. package/src/sdk/index.js +269 -0
  55. package/src/utils/callback-helper.js +198 -0
  56. package/test/callback-crypto.test.js +55 -0
  57. package/test/crypto.test.js +85 -0
  58. package/test/permission.test.js +115 -0
@@ -0,0 +1,402 @@
1
+ /**
2
+ * 消息收发模块
3
+ * API 章节:八 - 消息接收与发送
4
+ * 包含:发送消息、接收消息、群聊管理、智能机器人
5
+ */
6
+
7
+ const WeComSDK = require('../../sdk');
8
+
9
+ class Message extends WeComSDK {
10
+ constructor(config) {
11
+ super(config);
12
+ }
13
+
14
+ // ========== 应用消息 ==========
15
+
16
+ /**
17
+ * 发送应用消息
18
+ * @param {string} toUser 接收成员
19
+ * @param {number} agentId 应用 id
20
+ * @param {object} content 消息内容
21
+ * @param {string} msgType 消息类型
22
+ */
23
+ async sendMessage(toUser, agentId, content, msgType = 'text') {
24
+ return this.post('/message/send', {
25
+ touser: toUser,
26
+ agentid: agentId,
27
+ msgtype: msgType,
28
+ [msgType]: content
29
+ });
30
+ }
31
+
32
+ /**
33
+ * 发送文本消息
34
+ * @param {string} toUser 接收成员 (| 分隔)
35
+ * @param {string} content 文本内容
36
+ * @param {number} agentId 应用 id
37
+ */
38
+ async sendText(toUser, content, agentId) {
39
+ return this.sendMessage(toUser, agentId, { content }, 'text');
40
+ }
41
+
42
+ /**
43
+ * 发送图片消息
44
+ * @param {string} toUser 接收成员
45
+ * @param {string} mediaId 图片 media_id
46
+ * @param {number} agentId 应用 id
47
+ */
48
+ async sendImage(toUser, mediaId, agentId) {
49
+ return this.sendMessage(toUser, agentId, { media_id: mediaId }, 'image');
50
+ }
51
+
52
+ /**
53
+ * 发送语音消息
54
+ * @param {string} toUser 接收成员
55
+ * @param {string} mediaId 语音 media_id
56
+ * @param {number} agentId 应用 id
57
+ */
58
+ async sendVoice(toUser, mediaId, agentId) {
59
+ return this.sendMessage(toUser, agentId, { media_id: mediaId }, 'voice');
60
+ }
61
+
62
+ /**
63
+ * 发送视频消息
64
+ * @param {string} toUser 接收成员
65
+ * @param {string} mediaId 视频 media_id
66
+ * @param {number} agentId 应用 id
67
+ */
68
+ async sendVideo(toUser, mediaId, agentId) {
69
+ return this.sendMessage(toUser, agentId, { media_id: mediaId }, 'video');
70
+ }
71
+
72
+ /**
73
+ * 发送文件消息
74
+ * @param {string} toUser 接收成员
75
+ * @param {string} mediaId 文件 media_id
76
+ * @param {number} agentId 应用 id
77
+ */
78
+ async sendFile(toUser, mediaId, agentId) {
79
+ return this.sendMessage(toUser, agentId, { media_id: mediaId }, 'file');
80
+ }
81
+
82
+ /**
83
+ * 发送文本卡片消息
84
+ * @param {string} toUser 接收成员
85
+ * @param {object} content 卡片内容
86
+ * @param {number} agentId 应用 id
87
+ */
88
+ async sendTextCard(toUser, content, agentId) {
89
+ return this.sendMessage(toUser, agentId, content, 'textcard');
90
+ }
91
+
92
+ /**
93
+ * 发送图文消息
94
+ * @param {string} toUser 接收成员
95
+ * @param {object} content 图文内容
96
+ * @param {number} agentId 应用 id
97
+ */
98
+ async sendNews(toUser, content, agentId) {
99
+ return this.sendMessage(toUser, agentId, { articles: content }, 'news');
100
+ }
101
+
102
+ /**
103
+ * 发送 Markdown 消息
104
+ * @param {string} toUser 接收成员
105
+ * @param {string} content Markdown 内容
106
+ * @param {number} agentId 应用 id
107
+ */
108
+ async sendMarkdown(toUser, content, agentId) {
109
+ return this.sendMessage(toUser, agentId, { content }, 'markdown');
110
+ }
111
+
112
+ /**
113
+ * 发送模板卡片消息
114
+ * @param {string} toUser 接收成员
115
+ * @param {object} content 卡片内容
116
+ * @param {number} agentId 应用 id
117
+ */
118
+ async sendTemplateCard(toUser, content, agentId) {
119
+ return this.sendMessage(toUser, agentId, content, 'template_card');
120
+ }
121
+
122
+ /**
123
+ * 更新模板卡片消息
124
+ * @param {string} userId 成员 id
125
+ * @param {string} agentId 应用 id
126
+ * @param {string} responseCode 回复代码
127
+ * @param {object} cardData 卡片数据
128
+ */
129
+ async updateTemplateCard(userId, agentId, responseCode, cardData) {
130
+ return this.post('/message/update_template_card', {
131
+ userid: userId,
132
+ agentid: agentId,
133
+ response_code: responseCode,
134
+ card_data: cardData
135
+ });
136
+ }
137
+
138
+ /**
139
+ * 撤回应用消息
140
+ * @param {string} msgId 消息 id
141
+ */
142
+ async recallMessage(msgId) {
143
+ return this.post('/message/recall', { msgid: msgId });
144
+ }
145
+
146
+ // ========== 群聊会话管理 ==========
147
+
148
+ /**
149
+ * 创建群聊会话
150
+ * @param {string} name 群名称
151
+ * @param {string} owner 群主 userid
152
+ * @param {string[]} userList 成员列表
153
+ */
154
+ async createChat(name, owner, userList) {
155
+ return this.post('/appchat/create', {
156
+ name,
157
+ owner,
158
+ userlist: userList
159
+ });
160
+ }
161
+
162
+ /**
163
+ * 修改群聊会话
164
+ * @param {string} chatId 群聊 id
165
+ * @param {object} params 修改参数
166
+ */
167
+ async updateChat(chatId, { name, owner, addUserList, removeUserList }) {
168
+ return this.post('/appchat/update', {
169
+ chatid: chatId,
170
+ name,
171
+ owner,
172
+ add_user_list: addUserList,
173
+ remove_user_list: removeUserList
174
+ });
175
+ }
176
+
177
+ /**
178
+ * 获取群聊会话
179
+ * @param {string} chatId 群聊 id
180
+ */
181
+ async getChat(chatId) {
182
+ return this.post('/appchat/get', { chatid: chatId });
183
+ }
184
+
185
+ /**
186
+ * 应用推送消息到群聊
187
+ * @param {string} chatId 群聊 id
188
+ * @param {object} content 消息内容
189
+ * @param {string} msgType 消息类型
190
+ */
191
+ async sendChatMessage(chatId, content, msgType = 'text') {
192
+ return this.post('/appchat/send', {
193
+ chatid: chatId,
194
+ msgtype: msgType,
195
+ [msgType]: content
196
+ });
197
+ }
198
+
199
+ // ========== 智能表格自动化创建的群聊 ==========
200
+
201
+ /**
202
+ * 获取群聊列表
203
+ * @param {number} offset 偏移量
204
+ * @param {number} size 每页数量
205
+ */
206
+ async getOpenChatList(offset = 0, size = 100) {
207
+ return this.post('/openchat/list', { offset, limit: size });
208
+ }
209
+
210
+ /**
211
+ * 获取群聊详情
212
+ * @param {string} openChatId 群聊 id
213
+ */
214
+ async getOpenChatDetail(openChatId) {
215
+ return this.post('/openchat/get', { open_chatid: openChatId });
216
+ }
217
+
218
+ /**
219
+ * 修改群聊会话(智能表格)
220
+ * @param {string} openChatId 群聊 id
221
+ * @param {string} name 群名称
222
+ * @param {string} owner 群主
223
+ */
224
+ async updateOpenChat(openChatId, name, owner) {
225
+ return this.post('/openchat/update', {
226
+ open_chatid: openChatId,
227
+ name,
228
+ owner
229
+ });
230
+ }
231
+
232
+ // ========== 消息推送(群机器人) ==========
233
+
234
+ /**
235
+ * 机器人发送消息
236
+ * @param {string} webhookKey webhook key
237
+ * @param {object} content 消息内容
238
+ * @param {string} msgType 消息类型
239
+ */
240
+ async sendRobotMessage(webhookKey, content, msgType = 'text') {
241
+ const url = `https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${webhookKey}`;
242
+ return this.request({
243
+ method: 'POST',
244
+ url,
245
+ data: {
246
+ msgtype: msgType,
247
+ [msgType]: content
248
+ }
249
+ });
250
+ }
251
+
252
+ /**
253
+ * 机器人发送文本
254
+ * @param {string} webhookKey webhook key
255
+ * @param {string} content 文本内容
256
+ * @param {string[]} mentionedList @成员列表
257
+ */
258
+ async sendRobotText(webhookKey, content, mentionedList = []) {
259
+ return this.sendRobotMessage(webhookKey, {
260
+ content,
261
+ mentioned_list: mentionedList
262
+ }, 'text');
263
+ }
264
+
265
+ /**
266
+ * 机器人发送 Markdown
267
+ * @param {string} webhookKey webhook key
268
+ * @param {string} content Markdown 内容
269
+ */
270
+ async sendRobotMarkdown(webhookKey, content) {
271
+ return this.sendRobotMessage(webhookKey, { content }, 'markdown');
272
+ }
273
+
274
+ /**
275
+ * 机器人发送图片
276
+ * @param {string} webhookKey webhook key
277
+ * @param {string} base64 图片 base64
278
+ * @param {string} md5 图片 md5
279
+ */
280
+ async sendRobotImage(webhookKey, base64, md5) {
281
+ return this.sendRobotMessage(webhookKey, {
282
+ base64,
283
+ md5
284
+ }, 'image');
285
+ }
286
+
287
+ /**
288
+ * 机器人发送图文
289
+ * @param {string} webhookKey webhook key
290
+ * @param {object} news 图文内容
291
+ */
292
+ async sendRobotNews(webhookKey, news) {
293
+ return this.sendRobotMessage(webhookKey, { articles: news }, 'news');
294
+ }
295
+
296
+ // ========== 被动回复消息 ==========
297
+
298
+ /**
299
+ * 被动回复文本消息
300
+ * @param {string} toUser 接收者
301
+ * @param {string} fromUser 发送者
302
+ * @param {number} createTime 创建时间
303
+ * @param {string} content 文本内容
304
+ */
305
+ replyText(toUser, fromUser, createTime, content) {
306
+ return `<xml>
307
+ <ToUserName><![CDATA[${toUser}]]></ToUserName>
308
+ <FromUserName><![CDATA[${fromUser}]]></FromUserName>
309
+ <CreateTime>${createTime}</CreateTime>
310
+ <MsgType><![CDATA[text]]></MsgType>
311
+ <Content><![CDATA[${content}]]></Content>
312
+ </xml>`;
313
+ }
314
+
315
+ /**
316
+ * 被动回复图片消息
317
+ * @param {string} toUser 接收者
318
+ * @param {string} fromUser 发送者
319
+ * @param {number} createTime 创建时间
320
+ * @param {string} mediaId 图片 media_id
321
+ */
322
+ replyImage(toUser, fromUser, createTime, mediaId) {
323
+ return `<xml>
324
+ <ToUserName><![CDATA[${toUser}]]></ToUserName>
325
+ <FromUserName><![CDATA[${fromUser}]]></FromUserName>
326
+ <CreateTime>${createTime}</CreateTime>
327
+ <MsgType><![CDATA[image]]></MsgType>
328
+ <Image>
329
+ <MediaId><![CDATA[${mediaId}]]></MediaId>
330
+ </Image>
331
+ </xml>`;
332
+ }
333
+
334
+ /**
335
+ * 被动回复语音消息
336
+ * @param {string} toUser 接收者
337
+ * @param {string} fromUser 发送者
338
+ * @param {number} createTime 创建时间
339
+ * @param {string} mediaId 语音 media_id
340
+ */
341
+ replyVoice(toUser, fromUser, createTime, mediaId) {
342
+ return `<xml>
343
+ <ToUserName><![CDATA[${toUser}]]></ToUserName>
344
+ <FromUserName><![CDATA[${fromUser}]]></FromUserName>
345
+ <CreateTime>${createTime}</CreateTime>
346
+ <MsgType><![CDATA[voice]]></MsgType>
347
+ <Voice>
348
+ <MediaId><![CDATA[${mediaId}]]></MediaId>
349
+ </Voice>
350
+ </xml>`;
351
+ }
352
+
353
+ /**
354
+ * 被动回复视频消息
355
+ * @param {string} toUser 接收者
356
+ * @param {string} fromUser 发送者
357
+ * @param {number} createTime 创建时间
358
+ * @param {object} video 视频信息
359
+ */
360
+ replyVideo(toUser, fromUser, createTime, video) {
361
+ return `<xml>
362
+ <ToUserName><![CDATA[${toUser}]]></ToUserName>
363
+ <FromUserName><![CDATA[${fromUser}]]></FromUserName>
364
+ <CreateTime>${createTime}</CreateTime>
365
+ <MsgType><![CDATA[video]]></MsgType>
366
+ <Video>
367
+ <MediaId><![CDATA[${video.mediaId}]]></MediaId>
368
+ <Title><![CDATA[${video.title || ''}]]></Title>
369
+ <Description><![CDATA[${video.description || ''}]]></Description>
370
+ </Video>
371
+ </xml>`;
372
+ }
373
+
374
+ /**
375
+ * 被动回复图文消息
376
+ * @param {string} toUser 接收者
377
+ * @param {string} fromUser 发送者
378
+ * @param {number} createTime 创建时间
379
+ * @param {object[]} articles 图文列表
380
+ */
381
+ replyNews(toUser, fromUser, createTime, articles) {
382
+ const items = articles.map(item => `
383
+ <item>
384
+ <Title><![CDATA[${item.title}]]></Title>
385
+ <Description><![CDATA[${item.description || ''}]]></Description>
386
+ <PicUrl><![CDATA[${item.picUrl || ''}]]></PicUrl>
387
+ <Url><![CDATA[${item.url}]]></Url>
388
+ </item>
389
+ `).join('');
390
+
391
+ return `<xml>
392
+ <ToUserName><![CDATA[${toUser}]]></ToUserName>
393
+ <FromUserName><![CDATA[${fromUser}]]></FromUserName>
394
+ <CreateTime>${createTime}</CreateTime>
395
+ <MsgType><![CDATA[news]]></MsgType>
396
+ <ArticleCount>${articles.length}</ArticleCount>
397
+ <Articles>${items}</Articles>
398
+ </xml>`;
399
+ }
400
+ }
401
+
402
+ module.exports = Message;
@@ -0,0 +1,208 @@
1
+ /**
2
+ * 消息推送模块
3
+ * API 章节:十三 - 消息推送(企业群发)
4
+ * 包含:企业群发、欢迎语、提醒成员等
5
+ */
6
+
7
+ const WeComSDK = require('../../sdk');
8
+
9
+ class Messenger extends WeComSDK {
10
+ constructor(config) {
11
+ super(config);
12
+ }
13
+
14
+ // ========== 企业群发 ==========
15
+
16
+ /**
17
+ * 创建企业群发
18
+ * @param {string} userId 成员 ID
19
+ * @param {object} content 消息内容
20
+ * @param {string} chatId 群聊 ID(可选)
21
+ */
22
+ async createMassMessage(userId, content, chatId = '') {
23
+ const { text, image, video, file, link, miniprogram, msgType } = content;
24
+
25
+ const params = {
26
+ userid: userId,
27
+ msgtype: msgType || 'text'
28
+ };
29
+
30
+ if (chatId) params.chatid = chatId;
31
+
32
+ switch (params.msgtype) {
33
+ case 'text':
34
+ params.text = { content: text };
35
+ break;
36
+ case 'image':
37
+ params.image = { media_id: image };
38
+ break;
39
+ case 'video':
40
+ params.video = { media_id: video };
41
+ break;
42
+ case 'file':
43
+ params.file = { media_id: file };
44
+ break;
45
+ case 'link':
46
+ params.link = link;
47
+ break;
48
+ case 'miniprogram':
49
+ params.miniprogram = miniprogram;
50
+ break;
51
+ }
52
+
53
+ return this.post('/externalcontact/add_msg_template', params);
54
+ }
55
+
56
+ /**
57
+ * 获取企业的全部群发记录
58
+ * @param {number} startTime 开始时间戳
59
+ * @param {number} endTime 结束时间戳
60
+ * @param {string} userId 成员 ID(可选)
61
+ * @param {number} cursor 分页游标
62
+ * @param {number} size 每页数量
63
+ */
64
+ async getMassMessageList(startTime, endTime, userId = '', cursor = '', size = 100) {
65
+ return this.post('/externalcontact/get_moment_list', {
66
+ start_time: startTime,
67
+ end_time: endTime,
68
+ userid: userId,
69
+ cursor,
70
+ limit: size
71
+ });
72
+ }
73
+
74
+ /**
75
+ * 获取群发消息发送结果
76
+ * @param {string} msgId 消息 ID
77
+ */
78
+ async getMassMessageResult(msgId) {
79
+ return this.post('/externalcontact/get_moment_task_result', {
80
+ msg_id: msgId
81
+ });
82
+ }
83
+
84
+ /**
85
+ * 停止企业群发
86
+ * @param {string} msgId 消息 ID
87
+ */
88
+ async cancelMassMessage(msgId) {
89
+ return this.post('/externalcontact/cancel_moment_task', {
90
+ msg_id: msgId
91
+ });
92
+ }
93
+
94
+ // ========== 提醒成员群发 ==========
95
+
96
+ /**
97
+ * 提醒成员群发
98
+ * @param {string} userId 成员 ID
99
+ * @param {string} msgId 消息 ID
100
+ */
101
+ async remindMassMessage(userId, msgId) {
102
+ return this.post('/externalcontact/remind_moment_task', {
103
+ userid: userId,
104
+ msg_id: msgId
105
+ });
106
+ }
107
+
108
+ // ========== 欢迎语管理 ==========
109
+
110
+ /**
111
+ * 发送新客户欢迎语
112
+ * @param {string} userId 成员 ID
113
+ * @param {string} externalUserId 外部客户 ID
114
+ * @param {object} content 欢迎语内容
115
+ */
116
+ async sendWelcomeMessage(userId, externalUserId, content) {
117
+ const { text, image, video, file, link, miniprogram, msgType } = content;
118
+
119
+ const params = {
120
+ userid: userId,
121
+ external_userid: externalUserId,
122
+ msgtype: msgType || 'text'
123
+ };
124
+
125
+ switch (params.msgtype) {
126
+ case 'text':
127
+ params.text = { content: text };
128
+ break;
129
+ case 'image':
130
+ params.image = { media_id: image };
131
+ break;
132
+ case 'video':
133
+ params.video = { media_id: video };
134
+ break;
135
+ case 'file':
136
+ params.file = { media_id: file };
137
+ break;
138
+ case 'link':
139
+ params.link = link;
140
+ break;
141
+ case 'miniprogram':
142
+ params.miniprogram = miniprogram;
143
+ break;
144
+ }
145
+
146
+ return this.post('/externalcontact/send_welcome_msg', params);
147
+ }
148
+
149
+ /**
150
+ * 获取欢迎语素材列表
151
+ */
152
+ async getWelcomeMediaList() {
153
+ return this.post('/externalcontact/get_welcome_media', {});
154
+ }
155
+
156
+ /**
157
+ * 添加入群欢迎语素材
158
+ * @param {string} filePath 文件路径
159
+ * @param {string} type 素材类型
160
+ */
161
+ async uploadWelcomeMedia(filePath, type = 'image') {
162
+ return this.uploadFile(filePath, 'media', { type });
163
+ }
164
+
165
+ // ========== 入群欢迎语素材管理 ==========
166
+
167
+ /**
168
+ * 获取入群欢迎语素材
169
+ * @param {string} sceneId 场景 ID
170
+ */
171
+ async getGroupWelcomeMedia(sceneId) {
172
+ return this.post('/externalcontact/get_group_welcome_media', {
173
+ scene_id: sceneId
174
+ });
175
+ }
176
+
177
+ /**
178
+ * 配置入群欢迎语素材
179
+ * @param {object} params 欢迎语参数
180
+ */
181
+ async setGroupWelcomeMedia(params) {
182
+ return this.post('/externalcontact/set_group_welcome_media', params);
183
+ }
184
+
185
+ /**
186
+ * 删除入群欢迎语素材
187
+ * @param {string} sceneId 场景 ID
188
+ */
189
+ async deleteGroupWelcomeMedia(sceneId) {
190
+ return this.post('/externalcontact/del_group_welcome_media', {
191
+ scene_id: sceneId
192
+ });
193
+ }
194
+
195
+ // ========== 消息存档 ==========
196
+
197
+ /**
198
+ * 获取群发消息发送成员列表
199
+ * @param {string} msgId 消息 ID
200
+ */
201
+ async getMassMessageUsers(msgId) {
202
+ return this.post('/externalcontact/get_moment_task_detail', {
203
+ msg_id: msgId
204
+ });
205
+ }
206
+ }
207
+
208
+ module.exports = Messenger;