koishi-plugin-group-verification 1.0.21 → 1.0.23
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 +1 -0
- package/lib/index.js +44 -34
- package/package.json +1 -1
- package/readme.md +7 -1
- package/src/index.ts +71 -60
package/lib/index.d.ts
CHANGED
|
@@ -100,4 +100,5 @@ export declare function verifyApplication(config: GroupVerificationConfig, messa
|
|
|
100
100
|
matchedCount: number;
|
|
101
101
|
requiredThreshold: string;
|
|
102
102
|
}>;
|
|
103
|
+
export declare function handleFailedVerification(ctx: Context, session: any, config: GroupVerificationConfig, matchedCount?: number, requiredThreshold?: string): Promise<void>;
|
|
103
104
|
export declare function apply(ctx: Context, config: Config): void;
|
package/lib/index.js
CHANGED
|
@@ -22,6 +22,7 @@ var src_exports = {};
|
|
|
22
22
|
__export(src_exports, {
|
|
23
23
|
Config: () => Config,
|
|
24
24
|
apply: () => apply,
|
|
25
|
+
handleFailedVerification: () => handleFailedVerification,
|
|
25
26
|
inject: () => inject,
|
|
26
27
|
mergeReminder: () => mergeReminder,
|
|
27
28
|
name: () => name,
|
|
@@ -287,6 +288,47 @@ async function verifyApplication(config, message, session) {
|
|
|
287
288
|
return { isValid, matchedCount, requiredThreshold };
|
|
288
289
|
}
|
|
289
290
|
__name(verifyApplication, "verifyApplication");
|
|
291
|
+
async function handleFailedVerification(ctx, session, config, matchedCount, requiredThreshold) {
|
|
292
|
+
const guildId = (session.guildId || session.channelId || "").toString().trim();
|
|
293
|
+
const userId = session.userId;
|
|
294
|
+
if (!guildId) {
|
|
295
|
+
logger.warn("handleFailedVerification invoked without guildId, aborting");
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const username = session.username || "未知用户";
|
|
299
|
+
const message = session.content || "";
|
|
300
|
+
logger.info(`处理失败验证 guild=${guildId} user=${userId} msg="${message}" matched=${matchedCount} threshold=${requiredThreshold}`);
|
|
301
|
+
if (matchedCount === void 0 || requiredThreshold === void 0) {
|
|
302
|
+
const result = await verifyApplication(config, message, session);
|
|
303
|
+
matchedCount = result.matchedCount;
|
|
304
|
+
requiredThreshold = result.requiredThreshold;
|
|
305
|
+
}
|
|
306
|
+
let groupName = "未知群组";
|
|
307
|
+
try {
|
|
308
|
+
const guild = await session.bot.getGuild(guildId);
|
|
309
|
+
groupName = guild.name || groupName;
|
|
310
|
+
} catch (error) {
|
|
311
|
+
}
|
|
312
|
+
await ctx.database.create("group_verification_pending", {
|
|
313
|
+
groupId: guildId,
|
|
314
|
+
userId,
|
|
315
|
+
userName: username,
|
|
316
|
+
requestMessage: message,
|
|
317
|
+
applyTime: (/* @__PURE__ */ new Date()).toISOString()
|
|
318
|
+
});
|
|
319
|
+
if (!config.reminderEnabled || !config.reminderMessage || config.reminderMessage === "") {
|
|
320
|
+
logger.info(`群 ${guildId} 的提醒消息已被禁用,跳过发送`);
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
let reminderMsg = config.reminderMessage;
|
|
324
|
+
reminderMsg = reminderMsg.replace(/{user}/g, username).replace(/{id}/g, userId).replace(/{group}/g, guildId).replace(/{gname}/g, groupName).replace(/{question}/g, message).replace(/{answer}/g, matchedCount.toString()).replace(/{threshold}/g, requiredThreshold);
|
|
325
|
+
const rawChannel = (session.channelId || "").toString().trim();
|
|
326
|
+
const channel = rawChannel || guildId;
|
|
327
|
+
const target = rawChannel ? [channel, guildId] : guildId;
|
|
328
|
+
logger.debug("broadcast target", { channel, guildId, target });
|
|
329
|
+
await ctx.broadcast([target], reminderMsg);
|
|
330
|
+
}
|
|
331
|
+
__name(handleFailedVerification, "handleFailedVerification");
|
|
290
332
|
function apply(ctx, config) {
|
|
291
333
|
ctx.model.extend("group_verification_config", {
|
|
292
334
|
id: "unsigned",
|
|
@@ -367,7 +409,7 @@ function apply(ctx, config) {
|
|
|
367
409
|
}
|
|
368
410
|
}
|
|
369
411
|
} else {
|
|
370
|
-
await handleFailedVerification(ctx, session, config2);
|
|
412
|
+
await handleFailedVerification(ctx, session, config2, matchedCount, requiredThreshold);
|
|
371
413
|
}
|
|
372
414
|
});
|
|
373
415
|
ctx.on("guild-member-added", async (session) => {
|
|
@@ -393,39 +435,6 @@ function apply(ctx, config) {
|
|
|
393
435
|
logger.info(`用户 ${userId} 被手动邀请加入群 ${groupId},手动批准统计已更新`);
|
|
394
436
|
}
|
|
395
437
|
});
|
|
396
|
-
async function handleFailedVerification(ctx2, session, config2, matchedCount, requiredThreshold) {
|
|
397
|
-
const guildId = (session.guildId || session.channelId || "").toString().trim();
|
|
398
|
-
const userId = session.userId;
|
|
399
|
-
const username = session.username || "未知用户";
|
|
400
|
-
const message = session.content || "";
|
|
401
|
-
logger.info(`处理失败验证 guild=${guildId} user=${userId} msg="${message}" matched=${matchedCount} threshold=${requiredThreshold}`);
|
|
402
|
-
if (matchedCount === void 0 || requiredThreshold === void 0) {
|
|
403
|
-
const result = await verifyApplication(config2, message, session);
|
|
404
|
-
matchedCount = result.matchedCount;
|
|
405
|
-
requiredThreshold = result.requiredThreshold;
|
|
406
|
-
}
|
|
407
|
-
let groupName = "未知群组";
|
|
408
|
-
try {
|
|
409
|
-
const guild = await session.bot.getGuild(guildId);
|
|
410
|
-
groupName = guild.name || groupName;
|
|
411
|
-
} catch (error) {
|
|
412
|
-
}
|
|
413
|
-
await ctx2.database.create("group_verification_pending", {
|
|
414
|
-
groupId: guildId,
|
|
415
|
-
userId,
|
|
416
|
-
userName: username,
|
|
417
|
-
requestMessage: message,
|
|
418
|
-
applyTime: (/* @__PURE__ */ new Date()).toISOString()
|
|
419
|
-
});
|
|
420
|
-
if (!config2.reminderEnabled || !config2.reminderMessage || config2.reminderMessage === "") {
|
|
421
|
-
logger.info(`群 ${guildId} 的提醒消息已被禁用,跳过发送`);
|
|
422
|
-
return;
|
|
423
|
-
}
|
|
424
|
-
let reminderMsg = config2.reminderMessage;
|
|
425
|
-
reminderMsg = reminderMsg.replace(/{user}/g, username).replace(/{id}/g, userId).replace(/{group}/g, guildId).replace(/{gname}/g, groupName).replace(/{question}/g, message).replace(/{answer}/g, matchedCount.toString()).replace(/{threshold}/g, requiredThreshold);
|
|
426
|
-
await ctx2.broadcast([guildId], reminderMsg);
|
|
427
|
-
}
|
|
428
|
-
__name(handleFailedVerification, "handleFailedVerification");
|
|
429
438
|
async function updateStats(groupId, action) {
|
|
430
439
|
const existingStats = await ctx.database.get("group_verification_stats", { groupId });
|
|
431
440
|
if (existingStats.length > 0) {
|
|
@@ -1155,6 +1164,7 @@ __name(apply, "apply");
|
|
|
1155
1164
|
0 && (module.exports = {
|
|
1156
1165
|
Config,
|
|
1157
1166
|
apply,
|
|
1167
|
+
handleFailedVerification,
|
|
1158
1168
|
inject,
|
|
1159
1169
|
mergeReminder,
|
|
1160
1170
|
name,
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -146,7 +146,13 @@ group-verify.stats total
|
|
|
146
146
|
- **手动批准**:管理员手动同意的用户数
|
|
147
147
|
- **拒绝**:被拒绝的申请数
|
|
148
148
|
- **手动入群**:管理员直接邀请入群的用户数
|
|
149
|
-
|
|
149
|
+
### ⚠️ OneBot/QQ 适配器注意
|
|
150
|
+
默认情况下插件会使用 `ctx.broadcast` 发送提醒消息,
|
|
151
|
+
为了兼容 OneBot、QQ 等需要同时指定频道和群号的协议,
|
|
152
|
+
插件会自动将 `session.channelId` 与 `session.guildId` 一起
|
|
153
|
+
传给 `broadcast`。如果你使用的适配器出现无法发送消息的
|
|
154
|
+
情况,请确保群号与频道 ID 正确无空格,或者手动在配置
|
|
155
|
+
中补充 channelId(目前是自动处理)。
|
|
150
156
|
## 🛠️ 开发配置
|
|
151
157
|
|
|
152
158
|
### 全局配置
|
package/src/index.ts
CHANGED
|
@@ -405,6 +405,76 @@ export async function verifyApplication(config: GroupVerificationConfig, message
|
|
|
405
405
|
return { isValid, matchedCount, requiredThreshold }
|
|
406
406
|
}
|
|
407
407
|
|
|
408
|
+
// 处理验证失败的情况并发送提醒消息(可由 tests 调用)
|
|
409
|
+
export async function handleFailedVerification(
|
|
410
|
+
ctx: Context,
|
|
411
|
+
session: any,
|
|
412
|
+
config: GroupVerificationConfig,
|
|
413
|
+
matchedCount?: number,
|
|
414
|
+
requiredThreshold?: string
|
|
415
|
+
) {
|
|
416
|
+
const guildId = (session.guildId || session.channelId || '').toString().trim();
|
|
417
|
+
const userId = session.userId
|
|
418
|
+
// 如果没有可用的群号,直接退出(防止错误插入数据库)
|
|
419
|
+
if (!guildId) {
|
|
420
|
+
logger.warn('handleFailedVerification invoked without guildId, aborting')
|
|
421
|
+
return
|
|
422
|
+
}
|
|
423
|
+
const username = session.username || '未知用户'
|
|
424
|
+
const message = session.content || ''
|
|
425
|
+
logger.info(`处理失败验证 guild=${guildId} user=${userId} msg="${message}" matched=${matchedCount} threshold=${requiredThreshold}`)
|
|
426
|
+
// 如果未传入匹配信息,则重新计算一次(老调用)
|
|
427
|
+
if (matchedCount === undefined || requiredThreshold === undefined) {
|
|
428
|
+
const result = await verifyApplication(config, message, session)
|
|
429
|
+
matchedCount = result.matchedCount
|
|
430
|
+
requiredThreshold = result.requiredThreshold
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// 获取群信息
|
|
434
|
+
let groupName = '未知群组'
|
|
435
|
+
try {
|
|
436
|
+
const guild = await session.bot.getGuild(guildId)
|
|
437
|
+
groupName = guild.name || groupName
|
|
438
|
+
} catch (error) {
|
|
439
|
+
// 无法获取群名称时使用默认值
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// 将申请加入待审核列表
|
|
443
|
+
await ctx.database.create('group_verification_pending', {
|
|
444
|
+
groupId: guildId,
|
|
445
|
+
userId: userId,
|
|
446
|
+
userName: username,
|
|
447
|
+
requestMessage: message,
|
|
448
|
+
applyTime: new Date().toISOString()
|
|
449
|
+
})
|
|
450
|
+
// 如果提醒消息被禁用,直接返回
|
|
451
|
+
if (!config.reminderEnabled || !config.reminderMessage || config.reminderMessage === '') {
|
|
452
|
+
logger.info(`群 ${guildId} 的提醒消息已被禁用,跳过发送`)
|
|
453
|
+
return
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// 替换提醒消息中的变量
|
|
457
|
+
let reminderMsg = config.reminderMessage
|
|
458
|
+
reminderMsg = reminderMsg
|
|
459
|
+
.replace(/{user}/g, username)
|
|
460
|
+
.replace(/{id}/g, userId)
|
|
461
|
+
.replace(/{group}/g, guildId)
|
|
462
|
+
.replace(/{gname}/g, groupName)
|
|
463
|
+
.replace(/{question}/g, message)
|
|
464
|
+
.replace(/{answer}/g, matchedCount!.toString())
|
|
465
|
+
.replace(/{threshold}/g, requiredThreshold!)
|
|
466
|
+
|
|
467
|
+
// 发送提醒消息到群内
|
|
468
|
+
// OneBot 等适配器需要同时指定 channelId 与 guildId,否则会无法定位到具体频道
|
|
469
|
+
// ctx.broadcast 接收的元素可以是字符串、[channel, guild] 或者 session
|
|
470
|
+
const rawChannel = (session.channelId || '').toString().trim()
|
|
471
|
+
const channel = rawChannel || guildId
|
|
472
|
+
const target: string | [string, string] = rawChannel ? [channel, guildId] : guildId
|
|
473
|
+
logger.debug('broadcast target', { channel, guildId, target })
|
|
474
|
+
// cast to any to satisfy overloaded typings on ctx.broadcast
|
|
475
|
+
await (ctx.broadcast as any)([target], reminderMsg)
|
|
476
|
+
}
|
|
477
|
+
|
|
408
478
|
export function apply(ctx: Context, config: Config) {
|
|
409
479
|
// 创建数据库表
|
|
410
480
|
ctx.model.extend('group_verification_config', {
|
|
@@ -511,7 +581,7 @@ export function apply(ctx: Context, config: Config) {
|
|
|
511
581
|
}
|
|
512
582
|
}
|
|
513
583
|
} else {
|
|
514
|
-
await handleFailedVerification(ctx, session, config);
|
|
584
|
+
await handleFailedVerification(ctx, session, config, matchedCount, requiredThreshold);
|
|
515
585
|
}
|
|
516
586
|
});
|
|
517
587
|
|
|
@@ -548,65 +618,6 @@ export function apply(ctx: Context, config: Config) {
|
|
|
548
618
|
}
|
|
549
619
|
})
|
|
550
620
|
|
|
551
|
-
// 处理验证失败的情况
|
|
552
|
-
// 处理验证失败的情况并发送提醒消息
|
|
553
|
-
// matchedCount/requiredThreshold 可选,为空时内部重新计算(兼容旧调用)
|
|
554
|
-
async function handleFailedVerification(
|
|
555
|
-
ctx: Context,
|
|
556
|
-
session: any,
|
|
557
|
-
config: GroupVerificationConfig,
|
|
558
|
-
matchedCount?: number,
|
|
559
|
-
requiredThreshold?: string
|
|
560
|
-
) {
|
|
561
|
-
const guildId = (session.guildId || session.channelId || '').toString().trim();
|
|
562
|
-
const userId = session.userId
|
|
563
|
-
const username = session.username || '未知用户'
|
|
564
|
-
const message = session.content || ''
|
|
565
|
-
logger.info(`处理失败验证 guild=${guildId} user=${userId} msg="${message}" matched=${matchedCount} threshold=${requiredThreshold}`)
|
|
566
|
-
// 如果未传入匹配信息,则重新计算一次(老调用)
|
|
567
|
-
if (matchedCount === undefined || requiredThreshold === undefined) {
|
|
568
|
-
const result = await verifyApplication(config, message, session)
|
|
569
|
-
matchedCount = result.matchedCount
|
|
570
|
-
requiredThreshold = result.requiredThreshold
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
// 获取群信息
|
|
574
|
-
let groupName = '未知群组'
|
|
575
|
-
try {
|
|
576
|
-
const guild = await session.bot.getGuild(guildId)
|
|
577
|
-
groupName = guild.name || groupName
|
|
578
|
-
} catch (error) {
|
|
579
|
-
// 无法获取群名称时使用默认值
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
// 将申请加入待审核列表
|
|
583
|
-
await ctx.database.create('group_verification_pending', {
|
|
584
|
-
groupId: guildId,
|
|
585
|
-
userId: userId,
|
|
586
|
-
userName: username,
|
|
587
|
-
requestMessage: message,
|
|
588
|
-
applyTime: new Date().toISOString()
|
|
589
|
-
})
|
|
590
|
-
// 如果提醒消息被禁用,直接返回
|
|
591
|
-
if (!config.reminderEnabled || !config.reminderMessage || config.reminderMessage === '') {
|
|
592
|
-
logger.info(`群 ${guildId} 的提醒消息已被禁用,跳过发送`)
|
|
593
|
-
return
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
// 替换提醒消息中的变量
|
|
597
|
-
let reminderMsg = config.reminderMessage
|
|
598
|
-
reminderMsg = reminderMsg
|
|
599
|
-
.replace(/{user}/g, username)
|
|
600
|
-
.replace(/{id}/g, userId)
|
|
601
|
-
.replace(/{group}/g, guildId)
|
|
602
|
-
.replace(/{gname}/g, groupName)
|
|
603
|
-
.replace(/{question}/g, message)
|
|
604
|
-
.replace(/{answer}/g, matchedCount!.toString())
|
|
605
|
-
.replace(/{threshold}/g, requiredThreshold!)
|
|
606
|
-
|
|
607
|
-
// 发送提醒消息到群内
|
|
608
|
-
await ctx.broadcast([guildId], reminderMsg)
|
|
609
|
-
}
|
|
610
621
|
|
|
611
622
|
|
|
612
623
|
// 更新统计信息
|