koishi-plugin-group-verification 1.0.17 → 1.0.19
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/lib/index.d.ts +5 -0
- package/lib/index.js +84 -44
- package/package.json +1 -1
- package/src/index.ts +113 -67
package/lib/index.d.ts
CHANGED
|
@@ -95,4 +95,9 @@ export declare function mergeReminder(existingConfig: any | null, cleanedOptions
|
|
|
95
95
|
* 若检测到格式错误(如纯空格分隔关键词),返回 error 字段。
|
|
96
96
|
*/
|
|
97
97
|
export declare function parseConfigArgs(raw: string): ParsedArgs;
|
|
98
|
+
export declare function verifyApplication(config: GroupVerificationConfig, message: string, session: any): Promise<{
|
|
99
|
+
isValid: boolean;
|
|
100
|
+
matchedCount: number;
|
|
101
|
+
requiredThreshold: string;
|
|
102
|
+
}>;
|
|
98
103
|
export declare function apply(ctx: Context, config: Config): void;
|
package/lib/index.js
CHANGED
|
@@ -26,11 +26,13 @@ __export(src_exports, {
|
|
|
26
26
|
mergeReminder: () => mergeReminder,
|
|
27
27
|
name: () => name,
|
|
28
28
|
parseConfigArgs: () => parseConfigArgs,
|
|
29
|
-
tokenize: () => tokenize
|
|
29
|
+
tokenize: () => tokenize,
|
|
30
|
+
verifyApplication: () => verifyApplication
|
|
30
31
|
});
|
|
31
32
|
module.exports = __toCommonJS(src_exports);
|
|
32
33
|
var import_koishi = require("koishi");
|
|
33
34
|
var name = "group-verification";
|
|
35
|
+
var logger = console;
|
|
34
36
|
var Config = import_koishi.Schema.object({
|
|
35
37
|
defaultReminderMessage: import_koishi.Schema.string().description("默认提醒消息模板").default("{user}({id}) 申请加入群 {gname}({group})\n申请理由:{question}\n匹配情况:{answer}/{threshold}"),
|
|
36
38
|
enableStrictGroupCheck: import_koishi.Schema.boolean().description("是否启用严格的群号检查(检查群号长度)").default(false),
|
|
@@ -140,7 +142,7 @@ function validateKeywordFormat(raw) {
|
|
|
140
142
|
return true;
|
|
141
143
|
}
|
|
142
144
|
__name(validateKeywordFormat, "validateKeywordFormat");
|
|
143
|
-
function mergeReminder(existingConfig, cleanedOptions, hasRealMessageParam, hasRealEnableMessageParam, hasRealDisableMessageParam,
|
|
145
|
+
function mergeReminder(existingConfig, cleanedOptions, hasRealMessageParam, hasRealEnableMessageParam, hasRealDisableMessageParam, logger2) {
|
|
144
146
|
let reminderEnabled = true;
|
|
145
147
|
let reminderMessage = "{user}({id}) 申请加入群 {gname}({group})\n申请理由:{question}\n匹配情况:{answer}/{threshold}";
|
|
146
148
|
if (existingConfig) {
|
|
@@ -149,15 +151,15 @@ function mergeReminder(existingConfig, cleanedOptions, hasRealMessageParam, hasR
|
|
|
149
151
|
}
|
|
150
152
|
if (hasRealDisableMessageParam) {
|
|
151
153
|
reminderEnabled = false;
|
|
152
|
-
|
|
154
|
+
logger2.info("禁用提醒消息功能 (保留现有内容)");
|
|
153
155
|
} else if (hasRealEnableMessageParam) {
|
|
154
156
|
reminderEnabled = true;
|
|
155
|
-
|
|
157
|
+
logger2.info(`启用提醒消息(保留原消息): ${reminderMessage.substring(0, 50)}...`);
|
|
156
158
|
} else if (hasRealMessageParam) {
|
|
157
159
|
reminderEnabled = true;
|
|
158
160
|
if (cleanedOptions.message !== void 0) {
|
|
159
161
|
reminderMessage = cleanedOptions.message.replace(/\\n/g, "\n");
|
|
160
|
-
|
|
162
|
+
logger2.info(`设置自定义提醒消息: ${reminderMessage.substring(0, 50)}...`);
|
|
161
163
|
}
|
|
162
164
|
}
|
|
163
165
|
return { reminderEnabled, reminderMessage };
|
|
@@ -247,6 +249,44 @@ function parseConfigArgs(raw) {
|
|
|
247
249
|
return { keywords, flags, error };
|
|
248
250
|
}
|
|
249
251
|
__name(parseConfigArgs, "parseConfigArgs");
|
|
252
|
+
async function verifyApplication(config, message, session) {
|
|
253
|
+
const lowered = message.toLowerCase();
|
|
254
|
+
const matched = /* @__PURE__ */ new Set();
|
|
255
|
+
for (const keyword of config.keywords) {
|
|
256
|
+
if (lowered.includes(keyword.toLowerCase())) {
|
|
257
|
+
matched.add(keyword);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
const matchedCount = matched.size;
|
|
261
|
+
let isValid = false;
|
|
262
|
+
let requiredThreshold = "";
|
|
263
|
+
switch (config.reviewMethod) {
|
|
264
|
+
case 0:
|
|
265
|
+
isValid = true;
|
|
266
|
+
requiredThreshold = "null";
|
|
267
|
+
break;
|
|
268
|
+
case 1:
|
|
269
|
+
isValid = matchedCount >= (config.reviewParameters || 1);
|
|
270
|
+
requiredThreshold = `${config.reviewParameters || 1}`;
|
|
271
|
+
break;
|
|
272
|
+
case 2:
|
|
273
|
+
const ratio = matchedCount / config.keywords.length;
|
|
274
|
+
const requiredRatio = (config.reviewParameters || 100) / 100;
|
|
275
|
+
isValid = ratio >= requiredRatio;
|
|
276
|
+
requiredThreshold = `${config.reviewParameters || 100}%`;
|
|
277
|
+
break;
|
|
278
|
+
case 3:
|
|
279
|
+
isValid = false;
|
|
280
|
+
requiredThreshold = "null";
|
|
281
|
+
break;
|
|
282
|
+
default:
|
|
283
|
+
isValid = false;
|
|
284
|
+
requiredThreshold = "null";
|
|
285
|
+
}
|
|
286
|
+
logger.info(`verifyApplication msg="${message}" keywords=${JSON.stringify(config.keywords)} matched=${matchedCount} threshold=${requiredThreshold} valid=${isValid}`);
|
|
287
|
+
return { isValid, matchedCount, requiredThreshold };
|
|
288
|
+
}
|
|
289
|
+
__name(verifyApplication, "verifyApplication");
|
|
250
290
|
function apply(ctx, config) {
|
|
251
291
|
ctx.model.extend("group_verification_config", {
|
|
252
292
|
id: "unsigned",
|
|
@@ -265,7 +305,7 @@ function apply(ctx, config) {
|
|
|
265
305
|
primary: "id",
|
|
266
306
|
autoInc: true
|
|
267
307
|
});
|
|
268
|
-
|
|
308
|
+
logger = ctx.logger("group-verification");
|
|
269
309
|
logger.info("群组验证插件已启动");
|
|
270
310
|
logger.info(`默认提醒消息: ${config.defaultReminderMessage}`);
|
|
271
311
|
logger.info(`严格群号检查: ${config.enableStrictGroupCheck ? "启用" : "禁用"}`);
|
|
@@ -292,10 +332,17 @@ function apply(ctx, config) {
|
|
|
292
332
|
primary: "id",
|
|
293
333
|
autoInc: true
|
|
294
334
|
});
|
|
335
|
+
const autoQueue = /* @__PURE__ */ new Map();
|
|
295
336
|
ctx.on("guild-member-request", async (session) => {
|
|
296
|
-
|
|
337
|
+
logger.debug("guild-member-request event", session);
|
|
338
|
+
let guildId = (session.guildId || session.channelId || "").toString().trim();
|
|
297
339
|
const userId = session.userId;
|
|
298
340
|
const message = session.content || "";
|
|
341
|
+
if (!guildId) {
|
|
342
|
+
logger.warn("guild-member-request 没有 guildId,跳过处理");
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
const requestId = session.event?.requestId || session.messageId || "";
|
|
299
346
|
const groupConfig = await ctx.database.get("group_verification_config", {
|
|
300
347
|
groupId: guildId
|
|
301
348
|
});
|
|
@@ -304,8 +351,18 @@ function apply(ctx, config) {
|
|
|
304
351
|
}
|
|
305
352
|
const config2 = groupConfig[0];
|
|
306
353
|
const { isValid, matchedCount, requiredThreshold } = await verifyApplication(config2, message, session);
|
|
354
|
+
logger.info(`验证结果 guild=${guildId} user=${userId} msg="${message}" matched=${matchedCount} threshold=${requiredThreshold} valid=${isValid}`);
|
|
307
355
|
if (isValid) {
|
|
308
|
-
|
|
356
|
+
if (requestId) {
|
|
357
|
+
try {
|
|
358
|
+
await session.bot.handleGuildMemberRequest(requestId, true);
|
|
359
|
+
logger.info(`自动同意 requestId=${requestId}`);
|
|
360
|
+
if (!autoQueue.has(guildId)) autoQueue.set(guildId, /* @__PURE__ */ new Set());
|
|
361
|
+
autoQueue.get(guildId).add(userId);
|
|
362
|
+
} catch (e) {
|
|
363
|
+
logger.warn("自动同意失败", e);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
309
366
|
} else {
|
|
310
367
|
await handleFailedVerification(ctx, session, config2);
|
|
311
368
|
}
|
|
@@ -313,6 +370,13 @@ function apply(ctx, config) {
|
|
|
313
370
|
ctx.on("guild-member-added", async (session) => {
|
|
314
371
|
const groupId = session.guildId;
|
|
315
372
|
const userId = session.userId;
|
|
373
|
+
const set = autoQueue.get(groupId);
|
|
374
|
+
if (set && set.has(userId)) {
|
|
375
|
+
await updateStats(groupId, "autoApproved");
|
|
376
|
+
set.delete(userId);
|
|
377
|
+
logger.info(`用户 ${userId} 通过机器人审批加入群 ${groupId}(autoQueue),统计已更新`);
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
316
380
|
const pendingRecords = await ctx.database.get("group_verification_pending", {
|
|
317
381
|
groupId,
|
|
318
382
|
userId
|
|
@@ -345,6 +409,10 @@ function apply(ctx, config) {
|
|
|
345
409
|
requestMessage: message,
|
|
346
410
|
applyTime: /* @__PURE__ */ new Date()
|
|
347
411
|
});
|
|
412
|
+
if (!guildId) {
|
|
413
|
+
logger.warn("handleFailedVerification 收到无效 guildId,已放弃发送");
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
348
416
|
if (!config2.reminderEnabled || !config2.reminderMessage || config2.reminderMessage === "") {
|
|
349
417
|
logger.info(`群 ${guildId} 的提醒消息已被禁用,跳过发送`);
|
|
350
418
|
return;
|
|
@@ -354,38 +422,6 @@ function apply(ctx, config) {
|
|
|
354
422
|
await ctx2.broadcast([guildId], reminderMsg);
|
|
355
423
|
}
|
|
356
424
|
__name(handleFailedVerification, "handleFailedVerification");
|
|
357
|
-
async function verifyApplication(config2, message, session) {
|
|
358
|
-
const matchedCount = config2.keywords.filter(
|
|
359
|
-
(keyword) => message.toLowerCase().includes(keyword.toLowerCase())
|
|
360
|
-
).length;
|
|
361
|
-
let isValid = false;
|
|
362
|
-
let requiredThreshold = "";
|
|
363
|
-
switch (config2.reviewMethod) {
|
|
364
|
-
case 0:
|
|
365
|
-
isValid = true;
|
|
366
|
-
requiredThreshold = "null";
|
|
367
|
-
break;
|
|
368
|
-
case 1:
|
|
369
|
-
isValid = matchedCount >= (config2.reviewParameters || 1);
|
|
370
|
-
requiredThreshold = `${config2.reviewParameters || 1}`;
|
|
371
|
-
break;
|
|
372
|
-
case 2:
|
|
373
|
-
const ratio = matchedCount / config2.keywords.length;
|
|
374
|
-
const requiredRatio = (config2.reviewParameters || 100) / 100;
|
|
375
|
-
isValid = ratio >= requiredRatio;
|
|
376
|
-
requiredThreshold = `${config2.reviewParameters || 100}%`;
|
|
377
|
-
break;
|
|
378
|
-
case 3:
|
|
379
|
-
isValid = false;
|
|
380
|
-
requiredThreshold = "null";
|
|
381
|
-
break;
|
|
382
|
-
default:
|
|
383
|
-
isValid = false;
|
|
384
|
-
requiredThreshold = "null";
|
|
385
|
-
}
|
|
386
|
-
return { isValid, matchedCount, requiredThreshold };
|
|
387
|
-
}
|
|
388
|
-
__name(verifyApplication, "verifyApplication");
|
|
389
425
|
async function updateStats(groupId, action) {
|
|
390
426
|
const existingStats = await ctx.database.get("group_verification_stats", { groupId });
|
|
391
427
|
if (existingStats.length > 0) {
|
|
@@ -777,7 +813,8 @@ gvc -r # 删除配置`;
|
|
|
777
813
|
for (const request2 of pendingRequests2) {
|
|
778
814
|
try {
|
|
779
815
|
await ctx.database.remove("group_verification_pending", { id: request2.id });
|
|
780
|
-
|
|
816
|
+
if (!autoQueue.has(groupId)) autoQueue.set(groupId, /* @__PURE__ */ new Set());
|
|
817
|
+
autoQueue.get(groupId).add(request2.userId);
|
|
781
818
|
approvedCount++;
|
|
782
819
|
} catch (error) {
|
|
783
820
|
logger.warn(`处理申请 ${request2.id} 时出错:`, error);
|
|
@@ -793,7 +830,8 @@ gvc -r # 删除配置`;
|
|
|
793
830
|
try {
|
|
794
831
|
await session.bot.handleGuildMemberRequest(request2.userId, true);
|
|
795
832
|
await ctx.database.remove("group_verification_pending", { id: request2.id });
|
|
796
|
-
|
|
833
|
+
if (!autoQueue.has(groupId)) autoQueue.set(groupId, /* @__PURE__ */ new Set());
|
|
834
|
+
autoQueue.get(groupId).add(request2.userId);
|
|
797
835
|
return `已同意用户 ${request2.userName}(${request2.userId}) 的加群申请`;
|
|
798
836
|
} catch (error) {
|
|
799
837
|
return `处理申请时出错: ${error.message}`;
|
|
@@ -811,7 +849,8 @@ gvc -r # 删除配置`;
|
|
|
811
849
|
try {
|
|
812
850
|
await session.bot.handleGuildMemberRequest(request.userId, true);
|
|
813
851
|
await ctx.database.remove("group_verification_pending", { id: request.id });
|
|
814
|
-
|
|
852
|
+
if (!autoQueue.has(groupId)) autoQueue.set(groupId, /* @__PURE__ */ new Set());
|
|
853
|
+
autoQueue.get(groupId).add(userId);
|
|
815
854
|
return `已同意用户 ${request.userName}(${userId}) 的加群申请`;
|
|
816
855
|
} catch (error) {
|
|
817
856
|
return `处理申请时出错: ${error.message}`;
|
|
@@ -1083,5 +1122,6 @@ __name(apply, "apply");
|
|
|
1083
1122
|
mergeReminder,
|
|
1084
1123
|
name,
|
|
1085
1124
|
parseConfigArgs,
|
|
1086
|
-
tokenize
|
|
1125
|
+
tokenize,
|
|
1126
|
+
verifyApplication
|
|
1087
1127
|
});
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -2,6 +2,9 @@ import { Context, Schema, Session } from 'koishi'
|
|
|
2
2
|
|
|
3
3
|
export const name = 'group-verification'
|
|
4
4
|
|
|
5
|
+
// 模块级日志器,测试时使用 console
|
|
6
|
+
let logger: any = console
|
|
7
|
+
|
|
5
8
|
// 数据库模型定义
|
|
6
9
|
declare module 'koishi' {
|
|
7
10
|
interface Tables {
|
|
@@ -358,6 +361,50 @@ export function parseConfigArgs(raw: string): ParsedArgs {
|
|
|
358
361
|
|
|
359
362
|
return { keywords, flags, error };
|
|
360
363
|
}
|
|
364
|
+
|
|
365
|
+
// 验证申请(提取到外层,供测试调用)
|
|
366
|
+
export async function verifyApplication(config: GroupVerificationConfig, message: string, session: any): Promise<{isValid: boolean, matchedCount: number, requiredThreshold: string}> {
|
|
367
|
+
// 统计匹配的关键词数量(允许相互重叠)
|
|
368
|
+
const lowered = message.toLowerCase()
|
|
369
|
+
const matched = new Set<string>()
|
|
370
|
+
for (const keyword of config.keywords) {
|
|
371
|
+
if (lowered.includes(keyword.toLowerCase())) {
|
|
372
|
+
matched.add(keyword)
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
const matchedCount = matched.size
|
|
376
|
+
|
|
377
|
+
let isValid = false
|
|
378
|
+
let requiredThreshold = ''
|
|
379
|
+
|
|
380
|
+
switch (config.reviewMethod) {
|
|
381
|
+
case 0: // 全部同意
|
|
382
|
+
isValid = true
|
|
383
|
+
requiredThreshold = 'null'
|
|
384
|
+
break
|
|
385
|
+
case 1: // 按数量同意
|
|
386
|
+
isValid = matchedCount >= (config.reviewParameters || 1)
|
|
387
|
+
requiredThreshold = `${config.reviewParameters || 1}`
|
|
388
|
+
break
|
|
389
|
+
case 2: // 按比例同意
|
|
390
|
+
const ratio = matchedCount / config.keywords.length
|
|
391
|
+
const requiredRatio = (config.reviewParameters || 100) / 100
|
|
392
|
+
isValid = ratio >= requiredRatio
|
|
393
|
+
requiredThreshold = `${config.reviewParameters || 100}%`
|
|
394
|
+
break
|
|
395
|
+
case 3: // 全部拒绝
|
|
396
|
+
isValid = false
|
|
397
|
+
requiredThreshold = 'null'
|
|
398
|
+
break
|
|
399
|
+
default:
|
|
400
|
+
isValid = false
|
|
401
|
+
requiredThreshold = 'null'
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
logger.info(`verifyApplication msg="${message}" keywords=${JSON.stringify(config.keywords)} matched=${matchedCount} threshold=${requiredThreshold} valid=${isValid}`)
|
|
405
|
+
return { isValid, matchedCount, requiredThreshold }
|
|
406
|
+
}
|
|
407
|
+
|
|
361
408
|
export function apply(ctx: Context, config: Config) {
|
|
362
409
|
// 创建数据库表
|
|
363
410
|
ctx.model.extend('group_verification_config', {
|
|
@@ -377,8 +424,8 @@ export function apply(ctx: Context, config: Config) {
|
|
|
377
424
|
autoInc: true
|
|
378
425
|
})
|
|
379
426
|
|
|
380
|
-
// 获取logger
|
|
381
|
-
|
|
427
|
+
// 获取logger实例并保存到模块级变量
|
|
428
|
+
logger = ctx.logger('group-verification')
|
|
382
429
|
|
|
383
430
|
// 设置日志级别
|
|
384
431
|
// 注意:Koishi logger的level设置可能需要不同的方式
|
|
@@ -413,52 +460,78 @@ export function apply(ctx: Context, config: Config) {
|
|
|
413
460
|
autoInc: true
|
|
414
461
|
})
|
|
415
462
|
|
|
463
|
+
// 缓存正在审批的用户,用于避免 guild-member-added 重复计数
|
|
464
|
+
const autoQueue = new Map<string, Set<string>>();
|
|
465
|
+
|
|
416
466
|
// 监听加群申请事件
|
|
417
467
|
ctx.on('guild-member-request', async (session) => {
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
468
|
+
// debug: 输出整个 session 以便定位字段名
|
|
469
|
+
logger.debug('guild-member-request event', session)
|
|
470
|
+
|
|
471
|
+
let guildId = (session.guildId || session.channelId || '').toString().trim();
|
|
472
|
+
const userId = session.userId;
|
|
473
|
+
const message = session.content || '';
|
|
474
|
+
|
|
475
|
+
if (!guildId) {
|
|
476
|
+
logger.warn('guild-member-request 没有 guildId,跳过处理');
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// 获取 requestId(不同平台字段不同)
|
|
481
|
+
const requestId = ((session.event as any)?.requestId) || session.messageId || '';
|
|
482
|
+
|
|
422
483
|
// 获取群组配置
|
|
423
484
|
const groupConfig = await ctx.database.get('group_verification_config', {
|
|
424
485
|
groupId: guildId
|
|
425
|
-
})
|
|
426
|
-
|
|
486
|
+
});
|
|
487
|
+
|
|
427
488
|
if (!groupConfig || groupConfig.length === 0) {
|
|
428
|
-
//
|
|
429
|
-
|
|
430
|
-
// await session.bot.handleGuildMemberRequest(requestId, true)
|
|
431
|
-
return
|
|
489
|
+
// 无配置直接放行(需要有 requestId)
|
|
490
|
+
return;
|
|
432
491
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
492
|
+
const config = groupConfig[0];
|
|
493
|
+
|
|
494
|
+
// 执行验证,记录详细情况
|
|
495
|
+
const { isValid, matchedCount, requiredThreshold } = await verifyApplication(config, message, session);
|
|
496
|
+
logger.info(`验证结果 guild=${guildId} user=${userId} msg="${message}" matched=${matchedCount} threshold=${requiredThreshold} valid=${isValid}`);
|
|
497
|
+
|
|
439
498
|
if (isValid) {
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
499
|
+
if (requestId) {
|
|
500
|
+
try {
|
|
501
|
+
await session.bot.handleGuildMemberRequest(requestId, true);
|
|
502
|
+
logger.info(`自动同意 requestId=${requestId}`);
|
|
503
|
+
// 将此用户标记为自动批准,等待 guild-member-added 更新统计
|
|
504
|
+
if (!autoQueue.has(guildId)) autoQueue.set(guildId, new Set());
|
|
505
|
+
autoQueue.get(guildId)!.add(userId);
|
|
506
|
+
} catch (e) {
|
|
507
|
+
logger.warn('自动同意失败', e);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
445
510
|
} else {
|
|
446
|
-
|
|
447
|
-
await handleFailedVerification(ctx, session, config)
|
|
511
|
+
await handleFailedVerification(ctx, session, config);
|
|
448
512
|
}
|
|
449
|
-
})
|
|
513
|
+
});
|
|
450
514
|
|
|
451
515
|
// 监听群成员增加事件(包括手动邀请入群)
|
|
452
516
|
ctx.on('guild-member-added', async (session) => {
|
|
453
517
|
const groupId = session.guildId
|
|
454
518
|
const userId = session.userId
|
|
455
|
-
|
|
519
|
+
|
|
520
|
+
// 先检查 autoQueue
|
|
521
|
+
const set = autoQueue.get(groupId)
|
|
522
|
+
if (set && set.has(userId)) {
|
|
523
|
+
await updateStats(groupId, 'autoApproved')
|
|
524
|
+
set.delete(userId)
|
|
525
|
+
logger.info(`用户 ${userId} 通过机器人审批加入群 ${groupId}(autoQueue),统计已更新`)
|
|
526
|
+
return
|
|
527
|
+
}
|
|
528
|
+
|
|
456
529
|
// 检查是否有待审核记录
|
|
457
530
|
const pendingRecords = await ctx.database.get('group_verification_pending', {
|
|
458
531
|
groupId: groupId,
|
|
459
532
|
userId: userId
|
|
460
533
|
})
|
|
461
|
-
|
|
534
|
+
|
|
462
535
|
if (pendingRecords.length > 0) {
|
|
463
536
|
// 通过验证的用户入群,更新统计
|
|
464
537
|
await updateStats(groupId, 'autoApproved')
|
|
@@ -500,6 +573,11 @@ export function apply(ctx: Context, config: Config) {
|
|
|
500
573
|
applyTime: new Date()
|
|
501
574
|
})
|
|
502
575
|
|
|
576
|
+
// 如果 guildId 不合法,跳过
|
|
577
|
+
if (!guildId) {
|
|
578
|
+
logger.warn('handleFailedVerification 收到无效 guildId,已放弃发送')
|
|
579
|
+
return
|
|
580
|
+
}
|
|
503
581
|
// 如果提醒消息被禁用,直接返回
|
|
504
582
|
if (!config.reminderEnabled || !config.reminderMessage || config.reminderMessage === '') {
|
|
505
583
|
logger.info(`群 ${guildId} 的提醒消息已被禁用,跳过发送`)
|
|
@@ -521,42 +599,6 @@ export function apply(ctx: Context, config: Config) {
|
|
|
521
599
|
await ctx.broadcast([guildId], reminderMsg)
|
|
522
600
|
}
|
|
523
601
|
|
|
524
|
-
// 验证申请
|
|
525
|
-
async function verifyApplication(config: GroupVerificationConfig, message: string, session: any): Promise<{isValid: boolean, matchedCount: number, requiredThreshold: string}> {
|
|
526
|
-
// 统计匹配的关键词数量
|
|
527
|
-
const matchedCount = config.keywords.filter(keyword =>
|
|
528
|
-
message.toLowerCase().includes(keyword.toLowerCase())
|
|
529
|
-
).length
|
|
530
|
-
|
|
531
|
-
let isValid = false
|
|
532
|
-
let requiredThreshold = ''
|
|
533
|
-
|
|
534
|
-
switch (config.reviewMethod) {
|
|
535
|
-
case 0: // 全部同意
|
|
536
|
-
isValid = true
|
|
537
|
-
requiredThreshold = 'null'
|
|
538
|
-
break
|
|
539
|
-
case 1: // 按数量同意
|
|
540
|
-
isValid = matchedCount >= (config.reviewParameters || 1)
|
|
541
|
-
requiredThreshold = `${config.reviewParameters || 1}`
|
|
542
|
-
break
|
|
543
|
-
case 2: // 按比例同意
|
|
544
|
-
const ratio = matchedCount / config.keywords.length
|
|
545
|
-
const requiredRatio = (config.reviewParameters || 100) / 100
|
|
546
|
-
isValid = ratio >= requiredRatio
|
|
547
|
-
requiredThreshold = `${config.reviewParameters || 100}%`
|
|
548
|
-
break
|
|
549
|
-
case 3: // 全部拒绝
|
|
550
|
-
isValid = false
|
|
551
|
-
requiredThreshold = 'null'
|
|
552
|
-
break
|
|
553
|
-
default:
|
|
554
|
-
isValid = false
|
|
555
|
-
requiredThreshold = 'null'
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
return { isValid, matchedCount, requiredThreshold }
|
|
559
|
-
}
|
|
560
602
|
|
|
561
603
|
// 更新统计信息
|
|
562
604
|
async function updateStats(groupId: string, action: 'autoApproved' | 'manuallyApproved' | 'rejected') {
|
|
@@ -1084,7 +1126,9 @@ gvc -r # 删除配置`
|
|
|
1084
1126
|
// TODO: 需要获取实际的requestId来进行审批
|
|
1085
1127
|
// await session.bot.handleGuildMemberRequest(request.requestId, true)
|
|
1086
1128
|
await ctx.database.remove('group_verification_pending', { id: request.id })
|
|
1087
|
-
|
|
1129
|
+
// 标记为自动批准,实际统计在 guild-member-added 处理
|
|
1130
|
+
if (!autoQueue.has(groupId)) autoQueue.set(groupId, new Set())
|
|
1131
|
+
autoQueue.get(groupId)!.add(request.userId)
|
|
1088
1132
|
approvedCount++
|
|
1089
1133
|
} catch (error) {
|
|
1090
1134
|
logger.warn(`处理申请 ${request.id} 时出错:`, error)
|
|
@@ -1104,7 +1148,8 @@ gvc -r # 删除配置`
|
|
|
1104
1148
|
// 这里需要获取实际的requestId,暂时用userId作为示例
|
|
1105
1149
|
await session.bot.handleGuildMemberRequest(request.userId, true)
|
|
1106
1150
|
await ctx.database.remove('group_verification_pending', { id: request.id })
|
|
1107
|
-
|
|
1151
|
+
if (!autoQueue.has(groupId)) autoQueue.set(groupId, new Set())
|
|
1152
|
+
autoQueue.get(groupId)!.add(request.userId)
|
|
1108
1153
|
return `已同意用户 ${request.userName}(${request.userId}) 的加群申请`
|
|
1109
1154
|
} catch (error) {
|
|
1110
1155
|
return `处理申请时出错: ${error.message}`
|
|
@@ -1127,7 +1172,8 @@ gvc -r # 删除配置`
|
|
|
1127
1172
|
// 这里需要获取实际的requestId来进行审批
|
|
1128
1173
|
await session.bot.handleGuildMemberRequest(request.userId, true)
|
|
1129
1174
|
await ctx.database.remove('group_verification_pending', { id: request.id })
|
|
1130
|
-
|
|
1175
|
+
if (!autoQueue.has(groupId)) autoQueue.set(groupId, new Set())
|
|
1176
|
+
autoQueue.get(groupId)!.add(userId)
|
|
1131
1177
|
return `已同意用户 ${request.userName}(${userId}) 的加群申请`
|
|
1132
1178
|
} catch (error) {
|
|
1133
1179
|
return `处理申请时出错: ${error.message}`
|