koishi-plugin-group-verification 1.0.26 → 1.0.27

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 CHANGED
@@ -34,6 +34,7 @@ export interface PendingVerification {
34
34
  userId: string;
35
35
  userName: string;
36
36
  requestMessage: string;
37
+ requestId?: string;
37
38
  applyTime: string | Date;
38
39
  }
39
40
  export interface Config {
package/lib/index.js CHANGED
@@ -443,14 +443,19 @@ async function verifyApplication(config, message, session) {
443
443
  requiredThreshold = "null";
444
444
  break;
445
445
  case 1:
446
- isValid = matchedCount >= (config.reviewParameters || 1);
447
- requiredThreshold = `${config.reviewParameters || 1}`;
446
+ {
447
+ const thresholdNum = config.reviewParameters !== void 0 && config.reviewParameters !== null ? config.reviewParameters : 0;
448
+ isValid = matchedCount >= thresholdNum;
449
+ requiredThreshold = `${thresholdNum}`;
450
+ }
448
451
  break;
449
452
  case 2:
450
- const ratio = matchedCount / config.keywords.length;
451
- const requiredRatio = (config.reviewParameters || 100) / 100;
452
- isValid = ratio >= requiredRatio;
453
- requiredThreshold = `${config.reviewParameters || 100}%`;
453
+ {
454
+ const thresholdPct = config.reviewParameters !== void 0 && config.reviewParameters !== null ? config.reviewParameters : 100;
455
+ const ratio = matchedCount / config.keywords.length;
456
+ isValid = ratio >= thresholdPct / 100;
457
+ requiredThreshold = `${thresholdPct}%`;
458
+ }
454
459
  break;
455
460
  case 3:
456
461
  isValid = false;
@@ -485,11 +490,14 @@ async function handleFailedVerification(ctx, session, config, matchedCount, requ
485
490
  groupName = guild.name || groupName;
486
491
  } catch (error) {
487
492
  }
493
+ const requestId = session.event?.requestId || session.messageId || "";
494
+ await ctx.database.remove("group_verification_pending", { groupId: guildId, userId });
488
495
  await ctx.database.create("group_verification_pending", {
489
496
  groupId: guildId,
490
497
  userId,
491
498
  userName: username,
492
499
  requestMessage: message,
500
+ requestId,
493
501
  applyTime: (/* @__PURE__ */ new Date()).toISOString()
494
502
  });
495
503
  if (!config.reminderEnabled || !config.reminderMessage || config.reminderMessage === "") {
@@ -507,10 +515,18 @@ async function handleFailedVerification(ctx, session, config, matchedCount, requ
507
515
  await session.bot.broadcast([target], reminderMsg);
508
516
  } catch (err) {
509
517
  logger.warn("bot.broadcast failed, fallback to ctx.broadcast", err);
510
- await ctx.broadcast([target], reminderMsg);
518
+ if (typeof ctx.broadcast === "function") {
519
+ await ctx.broadcast([target], reminderMsg);
520
+ } else {
521
+ logger.info("ctx.broadcast 不可用,跳过发送");
522
+ }
511
523
  }
512
524
  } else {
513
- await ctx.broadcast([target], reminderMsg);
525
+ if (typeof ctx.broadcast === "function") {
526
+ await ctx.broadcast([target], reminderMsg);
527
+ } else {
528
+ logger.info("ctx.broadcast 不可用,跳过发送");
529
+ }
514
530
  }
515
531
  }
516
532
  __name(handleFailedVerification, "handleFailedVerification");
@@ -556,6 +572,8 @@ function apply(ctx, config) {
556
572
  userId: "string",
557
573
  userName: "string",
558
574
  requestMessage: "string",
575
+ // store the raw requestId if provided by OneBot event; used for approving/rejecting
576
+ requestId: "string",
559
577
  // record full timestamp as string to keep time component
560
578
  applyTime: "string"
561
579
  }, {
@@ -582,8 +600,10 @@ function apply(ctx, config) {
582
600
  });
583
601
  if (pendingRecords.length > 0) {
584
602
  await updateStats(ctx, groupId, "autoApproved");
585
- await ctx.database.remove("group_verification_pending", { id: pendingRecords[0].id });
586
- logger.info(`用户 ${userId} 通过验证加入群 ${groupId},统计已更新`);
603
+ for (const rec of pendingRecords) {
604
+ await ctx.database.remove("group_verification_pending", { id: rec.id });
605
+ }
606
+ logger.info(`用户 ${userId} 通过验证加入群 ${groupId},已清理 ${pendingRecords.length} 条待审核记录,统计已更新`);
587
607
  } else {
588
608
  await updateStats(ctx, groupId, "manuallyApproved");
589
609
  logger.info(`用户 ${userId} 被手动邀请加入群 ${groupId},手动批准统计已更新`);
@@ -898,7 +918,7 @@ ${debugInfo}`];
898
918
  const methodMap = { 0: "全部同意", 1: "按数量", 2: "按比例", 3: "全部拒绝" };
899
919
  feedbackMessage += `审核方式: ${methodMap[reviewMethod]}
900
920
  `;
901
- if (reviewParameters !== 0) {
921
+ if (reviewMethod === 1 || reviewMethod === 2) {
902
922
  const thresholdDisplay = reviewMethod === 2 ? `${reviewParameters}%` : reviewParameters.toString();
903
923
  feedbackMessage += `阈值: ${thresholdDisplay}
904
924
  `;
@@ -960,7 +980,11 @@ ${debugInfo}`];
960
980
  let approvedCount = 0;
961
981
  for (const request2 of pendingRequests2) {
962
982
  try {
983
+ if (request2.requestId) {
984
+ await session.bot.handleGuildMemberRequest(request2.requestId, true);
985
+ }
963
986
  await ctx.database.remove("group_verification_pending", { id: request2.id });
987
+ await updateStats(ctx, groupId, "manuallyApproved");
964
988
  approvedCount++;
965
989
  } catch (error) {
966
990
  logger.warn(`处理申请 ${request2.id} 时出错:`, error);
@@ -968,21 +992,25 @@ ${debugInfo}`];
968
992
  }
969
993
  return `已处理 ${approvedCount} 个加群申请`;
970
994
  } else {
971
- const recentRequest = await ctx.database.get("group_verification_pending", { groupId }, ["id", "userId", "userName"]);
972
- if (recentRequest.length === 0) {
995
+ let pending = await ctx.database.get("group_verification_pending", { groupId }, ["id", "userId", "userName", "applyTime"]);
996
+ if (pending.length === 0) {
973
997
  return "当前无待审核的加群申请";
974
998
  }
975
- const request2 = recentRequest[0];
999
+ pending.sort((a, b) => String(b.applyTime).localeCompare(String(a.applyTime)));
1000
+ const request2 = pending[0];
976
1001
  try {
977
- await session.bot.handleGuildMemberRequest(request2.userId, true);
978
- await ctx.database.remove("group_verification_pending", { id: request2.id });
1002
+ if (request2.requestId) {
1003
+ await session.bot.handleGuildMemberRequest(request2.requestId, true);
1004
+ }
1005
+ await ctx.database.remove("group_verification_pending", { groupId, userId: request2.userId });
1006
+ await updateStats(ctx, groupId, "manuallyApproved");
979
1007
  return `已同意用户 ${request2.userName}(${request2.userId}) 的加群申请`;
980
1008
  } catch (error) {
981
1009
  return `处理申请时出错: ${error.message}`;
982
1010
  }
983
1011
  }
984
1012
  }
985
- const pendingRequests = await ctx.database.get("group_verification_pending", {
1013
+ let pendingRequests = await ctx.database.get("group_verification_pending", {
986
1014
  groupId,
987
1015
  userId
988
1016
  });
@@ -991,8 +1019,11 @@ ${debugInfo}`];
991
1019
  }
992
1020
  const request = pendingRequests[0];
993
1021
  try {
994
- await session.bot.handleGuildMemberRequest(request.userId, true);
995
- await ctx.database.remove("group_verification_pending", { id: request.id });
1022
+ if (request.requestId) {
1023
+ await session.bot.handleGuildMemberRequest(request.requestId, true);
1024
+ }
1025
+ await ctx.database.remove("group_verification_pending", { groupId, userId });
1026
+ await updateStats(ctx, groupId, "manuallyApproved");
996
1027
  return `已同意用户 ${request.userName}(${userId}) 的加群申请`;
997
1028
  } catch (error) {
998
1029
  return `处理申请时出错: ${error.message}`;
@@ -1024,6 +1055,9 @@ ${debugInfo}`];
1024
1055
  let rejectedCount = 0;
1025
1056
  for (const request2 of pendingRequests2) {
1026
1057
  try {
1058
+ if (request2.requestId) {
1059
+ await session.bot.handleGuildMemberRequest(request2.requestId, false);
1060
+ }
1027
1061
  await ctx.database.remove("group_verification_pending", { id: request2.id });
1028
1062
  await updateStats(ctx, groupId, "rejected");
1029
1063
  rejectedCount++;
@@ -1033,13 +1067,17 @@ ${debugInfo}`];
1033
1067
  }
1034
1068
  return `已拒绝 ${rejectedCount} 个加群申请`;
1035
1069
  } else {
1036
- const recentRequest = await ctx.database.get("group_verification_pending", { groupId }, ["id", "userId", "userName"]);
1037
- if (recentRequest.length === 0) {
1070
+ let pending = await ctx.database.get("group_verification_pending", { groupId }, ["id", "userId", "userName", "applyTime"]);
1071
+ if (pending.length === 0) {
1038
1072
  return "当前无待审核的加群申请";
1039
1073
  }
1040
- const request2 = recentRequest[0];
1074
+ pending.sort((a, b) => String(b.applyTime).localeCompare(String(a.applyTime)));
1075
+ const request2 = pending[0];
1041
1076
  try {
1042
- await ctx.database.remove("group_verification_pending", { id: request2.id });
1077
+ if (request2.requestId) {
1078
+ await session.bot.handleGuildMemberRequest(request2.requestId, false);
1079
+ }
1080
+ await ctx.database.remove("group_verification_pending", { groupId, userId: request2.userId });
1043
1081
  await updateStats(ctx, groupId, "rejected");
1044
1082
  return `已拒绝用户 ${request2.userName}(${request2.userId}) 的加群申请`;
1045
1083
  } catch (error) {
@@ -1056,7 +1094,10 @@ ${debugInfo}`];
1056
1094
  }
1057
1095
  const request = pendingRequests[0];
1058
1096
  try {
1059
- await ctx.database.remove("group_verification_pending", { id: request.id });
1097
+ if (request.requestId) {
1098
+ await session.bot.handleGuildMemberRequest(request.requestId, false);
1099
+ }
1100
+ await ctx.database.remove("group_verification_pending", { groupId, userId });
1060
1101
  await updateStats(ctx, groupId, "rejected");
1061
1102
  return `已拒绝用户 ${request.userName}(${userId}) 的加群申请`;
1062
1103
  } catch (error) {
@@ -1211,6 +1252,7 @@ ${debugInfo}`];
1211
1252
  for (const p of pendings) {
1212
1253
  const updates = {};
1213
1254
  if (p.applyTime instanceof Date) updates.applyTime = p.applyTime.toISOString();
1255
+ if (p.requestId === void 0) updates.requestId = "";
1214
1256
  if (Object.keys(updates).length) {
1215
1257
  await ctx.database.set("group_verification_pending", { id: p.id }, updates);
1216
1258
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-group-verification",
3
3
  "description": "[WIP] Koishi 群组加群验证插件,支持多关键词匹配审核、多种审核方式和详细统计功能(开发中)",
4
- "version": "1.0.26",
4
+ "version": "1.0.27",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
package/src/index.ts CHANGED
@@ -46,6 +46,8 @@ export interface PendingVerification {
46
46
  userId: string
47
47
  userName: string
48
48
  requestMessage: string
49
+ // raw OneBot requestId (may be empty string)
50
+ requestId?: string
49
51
  applyTime: string | Date
50
52
  }
51
53
 
@@ -581,14 +583,24 @@ export async function verifyApplication(config: GroupVerificationConfig, message
581
583
  requiredThreshold = 'null'
582
584
  break
583
585
  case 1: // 按数量同意
584
- isValid = matchedCount >= (config.reviewParameters || 1)
585
- requiredThreshold = `${config.reviewParameters || 1}`
586
+ {
587
+ // threshold may legitimately be 0 (表示全部同意)
588
+ const thresholdNum = config.reviewParameters !== undefined && config.reviewParameters !== null
589
+ ? config.reviewParameters
590
+ : 0
591
+ isValid = matchedCount >= thresholdNum
592
+ requiredThreshold = `${thresholdNum}`
593
+ }
586
594
  break
587
595
  case 2: // 按比例同意
588
- const ratio = matchedCount / config.keywords.length
589
- const requiredRatio = (config.reviewParameters || 100) / 100
590
- isValid = ratio >= requiredRatio
591
- requiredThreshold = `${config.reviewParameters || 100}%`
596
+ {
597
+ const thresholdPct = config.reviewParameters !== undefined && config.reviewParameters !== null
598
+ ? config.reviewParameters
599
+ : 100
600
+ const ratio = matchedCount / config.keywords.length
601
+ isValid = ratio >= thresholdPct / 100
602
+ requiredThreshold = `${thresholdPct}%`
603
+ }
592
604
  break
593
605
  case 3: // 全部拒绝
594
606
  isValid = false
@@ -637,12 +649,19 @@ export async function handleFailedVerification(
637
649
  // 无法获取群名称时使用默认值
638
650
  }
639
651
 
652
+ // extract requestId if available (OneBot event attaches it)
653
+ const requestId = ((session.event as any)?.requestId) || session.messageId || ''
654
+
655
+ // 删除同一用户在该群之前的所有待审核记录,保留最新一个
656
+ await ctx.database.remove('group_verification_pending', { groupId: guildId, userId })
657
+
640
658
  // 将申请加入待审核列表
641
659
  await ctx.database.create('group_verification_pending', {
642
660
  groupId: guildId,
643
661
  userId: userId,
644
662
  userName: username,
645
663
  requestMessage: message,
664
+ requestId,
646
665
  applyTime: new Date().toISOString()
647
666
  })
648
667
  // 如果提醒消息被禁用,直接返回
@@ -676,10 +695,18 @@ export async function handleFailedVerification(
676
695
  } catch (err) {
677
696
  // fallback to ctx.broadcast if bot.broadcast fails for some reason
678
697
  logger.warn('bot.broadcast failed, fallback to ctx.broadcast', err)
679
- await (ctx.broadcast as any)([target], reminderMsg)
698
+ if (typeof (ctx.broadcast) === 'function') {
699
+ await (ctx.broadcast as any)([target], reminderMsg)
700
+ } else {
701
+ logger.info('ctx.broadcast 不可用,跳过发送')
702
+ }
680
703
  }
681
704
  } else {
682
- await (ctx.broadcast as any)([target], reminderMsg)
705
+ if (typeof (ctx.broadcast) === 'function') {
706
+ await (ctx.broadcast as any)([target], reminderMsg)
707
+ } else {
708
+ logger.info('ctx.broadcast 不可用,跳过发送')
709
+ }
683
710
  }
684
711
  }
685
712
 
@@ -728,15 +755,18 @@ export function apply(ctx: Context, config: Config) {
728
755
  autoInc: true
729
756
  })
730
757
 
758
+ // cast schema to any to avoid type conflicts when adding new fields
731
759
  ctx.model.extend('group_verification_pending', {
732
760
  id: 'unsigned',
733
761
  groupId: 'string',
734
762
  userId: 'string',
735
763
  userName: 'string',
736
764
  requestMessage: 'string',
765
+ // store the raw requestId if provided by OneBot event; used for approving/rejecting
766
+ requestId: 'string',
737
767
  // record full timestamp as string to keep time component
738
768
  applyTime: 'string'
739
- }, {
769
+ } as any, {
740
770
  primary: 'id',
741
771
  autoInc: true
742
772
  })
@@ -772,9 +802,11 @@ export function apply(ctx: Context, config: Config) {
772
802
  if (pendingRecords.length > 0) {
773
803
  // 通过验证的用户入群,更新统计
774
804
  await updateStats(ctx, groupId, 'autoApproved')
775
- // 清除待审核记录
776
- await ctx.database.remove('group_verification_pending', { id: pendingRecords[0].id })
777
- logger.info(`用户 ${userId} 通过验证加入群 ${groupId},统计已更新`)
805
+ // 清除所有该用户的待审核记录
806
+ for (const rec of pendingRecords) {
807
+ await ctx.database.remove('group_verification_pending', { id: rec.id })
808
+ }
809
+ logger.info(`用户 ${userId} 通过验证加入群 ${groupId},已清理 ${pendingRecords.length} 条待审核记录,统计已更新`)
778
810
  } else {
779
811
  // 手动邀请入群,记录到手动批准统计
780
812
  await updateStats(ctx, groupId, 'manuallyApproved')
@@ -1212,7 +1244,8 @@ export function apply(ctx: Context, config: Config) {
1212
1244
  const methodMap = {0: '全部同意', 1: '按数量', 2: '按比例', 3: '全部拒绝'}
1213
1245
  feedbackMessage += `审核方式: ${methodMap[reviewMethod]}\n`
1214
1246
 
1215
- if (reviewParameters !== 0) {
1247
+ // 显示阈值(即便为 0
1248
+ if (reviewMethod === 1 || reviewMethod === 2) {
1216
1249
  const thresholdDisplay = reviewMethod === 2 ? `${reviewParameters}%` : reviewParameters.toString()
1217
1250
  feedbackMessage += `阈值: ${thresholdDisplay}\n`
1218
1251
  }
@@ -1275,7 +1308,7 @@ export function apply(ctx: Context, config: Config) {
1275
1308
  if (configs.length > 0 && configs[0].reviewMethod === 3) {
1276
1309
  return '该群已设为全部拒绝,无法手动同意任何申请'
1277
1310
  }
1278
- // 处理默认情况和all情况
1311
+ // 处理默认情况和 all 情况
1279
1312
  if (!userId || userId.toLowerCase() === 'all') {
1280
1313
  if (userId?.toLowerCase() === 'all') {
1281
1314
  // 处理所有待审核申请
@@ -1287,9 +1320,11 @@ export function apply(ctx: Context, config: Config) {
1287
1320
  let approvedCount = 0
1288
1321
  for (const request of pendingRequests) {
1289
1322
  try {
1290
- // TODO: 需要获取实际的requestId来进行审批
1291
- // await session.bot.handleGuildMemberRequest(request.requestId, true)
1323
+ if (request.requestId) {
1324
+ await session.bot.handleGuildMemberRequest(request.requestId, true)
1325
+ }
1292
1326
  await ctx.database.remove('group_verification_pending', { id: request.id })
1327
+ await updateStats(ctx, groupId, 'manuallyApproved')
1293
1328
  approvedCount++
1294
1329
  } catch (error) {
1295
1330
  logger.warn(`处理申请 ${request.id} 时出错:`, error)
@@ -1298,17 +1333,20 @@ export function apply(ctx: Context, config: Config) {
1298
1333
 
1299
1334
  return `已处理 ${approvedCount} 个加群申请`
1300
1335
  } else {
1301
- // 处理最近的一个申请
1302
- const recentRequest = await ctx.database.get('group_verification_pending', { groupId }, ['id', 'userId', 'userName'])
1303
- if (recentRequest.length === 0) {
1336
+ // 处理最近的一个申请(按时间降序)
1337
+ let pending: any[] = await ctx.database.get('group_verification_pending', { groupId }, ['id', 'userId', 'userName', 'applyTime'])
1338
+ if (pending.length === 0) {
1304
1339
  return '当前无待审核的加群申请'
1305
1340
  }
1306
-
1307
- const request = recentRequest[0]
1341
+ pending.sort((a, b) => String(b.applyTime).localeCompare(String(a.applyTime)))
1342
+ const request: any = pending[0]
1308
1343
  try {
1309
- // 这里需要获取实际的requestId,暂时用userId作为示例
1310
- await session.bot.handleGuildMemberRequest(request.userId, true)
1311
- await ctx.database.remove('group_verification_pending', { id: request.id })
1344
+ if (request.requestId) {
1345
+ await session.bot.handleGuildMemberRequest(request.requestId, true)
1346
+ }
1347
+ // 清除该用户的所有待审核记录
1348
+ await ctx.database.remove('group_verification_pending', { groupId, userId: request.userId })
1349
+ await updateStats(ctx, groupId, 'manuallyApproved')
1312
1350
  return `已同意用户 ${request.userName}(${request.userId}) 的加群申请`
1313
1351
  } catch (error) {
1314
1352
  return `处理申请时出错: ${error.message}`
@@ -1317,7 +1355,7 @@ export function apply(ctx: Context, config: Config) {
1317
1355
  }
1318
1356
 
1319
1357
  // 处理指定用户ID的情况
1320
- const pendingRequests = await ctx.database.get('group_verification_pending', {
1358
+ let pendingRequests = await ctx.database.get('group_verification_pending', {
1321
1359
  groupId,
1322
1360
  userId: userId
1323
1361
  })
@@ -1328,9 +1366,12 @@ export function apply(ctx: Context, config: Config) {
1328
1366
 
1329
1367
  const request = pendingRequests[0]
1330
1368
  try {
1331
- // 这里需要获取实际的requestId来进行审批
1332
- await session.bot.handleGuildMemberRequest(request.userId, true)
1333
- await ctx.database.remove('group_verification_pending', { id: request.id })
1369
+ if (request.requestId) {
1370
+ await session.bot.handleGuildMemberRequest(request.requestId, true)
1371
+ }
1372
+ // 删除该用户的所有记录
1373
+ await ctx.database.remove('group_verification_pending', { groupId, userId })
1374
+ await updateStats(ctx, groupId, 'manuallyApproved')
1334
1375
  return `已同意用户 ${request.userName}(${userId}) 的加群申请`
1335
1376
  } catch (error) {
1336
1377
  return `处理申请时出错: ${error.message}`
@@ -1357,7 +1398,7 @@ export function apply(ctx: Context, config: Config) {
1357
1398
  return '请在群聊中使用此命令'
1358
1399
  }
1359
1400
 
1360
- // 处理默认情况和all情况
1401
+ // 处理默认情况和 all 情况
1361
1402
  if (!userId || userId.toLowerCase() === 'all') {
1362
1403
  if (userId?.toLowerCase() === 'all') {
1363
1404
  // 拒绝所有待审核申请
@@ -1369,8 +1410,9 @@ export function apply(ctx: Context, config: Config) {
1369
1410
  let rejectedCount = 0
1370
1411
  for (const request of pendingRequests) {
1371
1412
  try {
1372
- // TODO: 需要获取实际的requestId来进行拒绝
1373
- // await session.bot.handleGuildMemberRequest(request.requestId, false)
1413
+ if (request.requestId) {
1414
+ await session.bot.handleGuildMemberRequest(request.requestId, false)
1415
+ }
1374
1416
  await ctx.database.remove('group_verification_pending', { id: request.id })
1375
1417
  await updateStats(ctx, groupId, 'rejected')
1376
1418
  rejectedCount++
@@ -1381,17 +1423,19 @@ export function apply(ctx: Context, config: Config) {
1381
1423
 
1382
1424
  return `已拒绝 ${rejectedCount} 个加群申请`
1383
1425
  } else {
1384
- // 拒绝最近的一个申请
1385
- const recentRequest = await ctx.database.get('group_verification_pending', { groupId }, ['id', 'userId', 'userName'])
1386
- if (recentRequest.length === 0) {
1426
+ // 拒绝最近的一个申请(按 applyTime 降序)
1427
+ let pending: any[] = await ctx.database.get('group_verification_pending', { groupId }, ['id', 'userId', 'userName', 'applyTime'])
1428
+ if (pending.length === 0) {
1387
1429
  return '当前无待审核的加群申请'
1388
1430
  }
1389
-
1390
- const request = recentRequest[0]
1431
+ pending.sort((a, b) => String(b.applyTime).localeCompare(String(a.applyTime)))
1432
+ const request: any = pending[0]
1391
1433
  try {
1392
- // TODO: 需要获取实际的requestId来进行拒绝
1393
- // await session.bot.handleGuildMemberRequest(request.requestId, false)
1394
- await ctx.database.remove('group_verification_pending', { id: request.id })
1434
+ if (request.requestId) {
1435
+ await session.bot.handleGuildMemberRequest(request.requestId, false)
1436
+ }
1437
+ // 删除该用户的所有记录
1438
+ await ctx.database.remove('group_verification_pending', { groupId, userId: request.userId })
1395
1439
  await updateStats(ctx, groupId, 'rejected')
1396
1440
  return `已拒绝用户 ${request.userName}(${request.userId}) 的加群申请`
1397
1441
  } catch (error) {
@@ -1412,9 +1456,11 @@ export function apply(ctx: Context, config: Config) {
1412
1456
 
1413
1457
  const request = pendingRequests[0]
1414
1458
  try {
1415
- // TODO: 需要获取实际的requestId来进行拒绝
1416
- // await session.bot.handleGuildMemberRequest(request.requestId, false)
1417
- await ctx.database.remove('group_verification_pending', { id: request.id })
1459
+ if (request.requestId) {
1460
+ await session.bot.handleGuildMemberRequest(request.requestId, false)
1461
+ }
1462
+ // 删除该用户的所有记录
1463
+ await ctx.database.remove('group_verification_pending', { groupId, userId })
1418
1464
  await updateStats(ctx, groupId, 'rejected')
1419
1465
  return `已拒绝用户 ${request.userName}(${userId}) 的加群申请`
1420
1466
  } catch (error) {
@@ -1599,6 +1645,8 @@ export function apply(ctx: Context, config: Config) {
1599
1645
  for (const p of pendings) {
1600
1646
  const updates: any = {}
1601
1647
  if (p.applyTime instanceof Date) updates.applyTime = p.applyTime.toISOString()
1648
+ // add default empty requestId if record pre-dates the new column
1649
+ if (p.requestId === undefined) updates.requestId = ''
1602
1650
  if (Object.keys(updates).length) {
1603
1651
  await ctx.database.set('group_verification_pending', { id: p.id }, updates)
1604
1652
  }