koishi-plugin-group-verification 1.0.19 → 1.0.20

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
@@ -17,8 +17,8 @@ export interface GroupVerificationConfig {
17
17
  reminderMessage: string;
18
18
  createdBy: string;
19
19
  updatedBy: string;
20
- createdAt: Date;
21
- updatedAt: Date;
20
+ createdAt: string | Date;
21
+ updatedAt: string | Date;
22
22
  }
23
23
  export interface GroupVerificationStats {
24
24
  id: number;
@@ -26,7 +26,7 @@ export interface GroupVerificationStats {
26
26
  autoApproved: number;
27
27
  manuallyApproved: number;
28
28
  rejected: number;
29
- lastUpdated: Date;
29
+ lastUpdated: string | Date;
30
30
  }
31
31
  export interface PendingVerification {
32
32
  id: number;
@@ -34,7 +34,7 @@ export interface PendingVerification {
34
34
  userId: string;
35
35
  userName: string;
36
36
  requestMessage: string;
37
- applyTime: Date;
37
+ applyTime: string | Date;
38
38
  }
39
39
  export interface Config {
40
40
  defaultReminderMessage?: string;
package/lib/index.js CHANGED
@@ -299,8 +299,8 @@ function apply(ctx, config) {
299
299
  reminderMessage: "string",
300
300
  createdBy: "string",
301
301
  updatedBy: "string",
302
- createdAt: "date",
303
- updatedAt: "date"
302
+ createdAt: "string",
303
+ updatedAt: "string"
304
304
  }, {
305
305
  primary: "id",
306
306
  autoInc: true
@@ -316,7 +316,9 @@ function apply(ctx, config) {
316
316
  autoApproved: "integer",
317
317
  manuallyApproved: "integer",
318
318
  rejected: "integer",
319
- lastUpdated: "date"
319
+ // store as string (ISO timestamp) to preserve full date+time;
320
+ // Koishi `date` type truncates to day which leads to 00:00:00.
321
+ lastUpdated: "string"
320
322
  }, {
321
323
  primary: "id",
322
324
  autoInc: true
@@ -327,7 +329,8 @@ function apply(ctx, config) {
327
329
  userId: "string",
328
330
  userName: "string",
329
331
  requestMessage: "string",
330
- applyTime: "date"
332
+ // record full timestamp as string to keep time component
333
+ applyTime: "string"
331
334
  }, {
332
335
  primary: "id",
333
336
  autoInc: true
@@ -390,29 +393,30 @@ function apply(ctx, config) {
390
393
  logger.info(`用户 ${userId} 被手动邀请加入群 ${groupId},手动批准统计已更新`);
391
394
  }
392
395
  });
393
- async function handleFailedVerification(ctx2, session, config2) {
394
- const guildId = session.guildId;
396
+ async function handleFailedVerification(ctx2, session, config2, matchedCount, requiredThreshold) {
397
+ const guildId = (session.guildId || session.channelId || "").toString().trim();
395
398
  const userId = session.userId;
396
399
  const username = session.username || "未知用户";
397
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
+ }
398
407
  let groupName = "未知群组";
399
408
  try {
400
409
  const guild = await session.bot.getGuild(guildId);
401
410
  groupName = guild.name || groupName;
402
411
  } catch (error) {
403
412
  }
404
- const { matchedCount, requiredThreshold } = await verifyApplication(config2, message, session);
405
413
  await ctx2.database.create("group_verification_pending", {
406
414
  groupId: guildId,
407
415
  userId,
408
416
  userName: username,
409
417
  requestMessage: message,
410
- applyTime: /* @__PURE__ */ new Date()
418
+ applyTime: (/* @__PURE__ */ new Date()).toISOString()
411
419
  });
412
- if (!guildId) {
413
- logger.warn("handleFailedVerification 收到无效 guildId,已放弃发送");
414
- return;
415
- }
416
420
  if (!config2.reminderEnabled || !config2.reminderMessage || config2.reminderMessage === "") {
417
421
  logger.info(`群 ${guildId} 的提醒消息已被禁用,跳过发送`);
418
422
  return;
@@ -428,7 +432,7 @@ function apply(ctx, config) {
428
432
  const stats = existingStats[0];
429
433
  await ctx.database.set("group_verification_stats", { id: stats.id }, {
430
434
  [action]: stats[action] + 1,
431
- lastUpdated: /* @__PURE__ */ new Date()
435
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
432
436
  });
433
437
  } else {
434
438
  await ctx.database.create("group_verification_stats", {
@@ -436,7 +440,7 @@ function apply(ctx, config) {
436
440
  autoApproved: action === "autoApproved" ? 1 : 0,
437
441
  manuallyApproved: action === "manuallyApproved" ? 1 : 0,
438
442
  rejected: action === "rejected" ? 1 : 0,
439
- lastUpdated: /* @__PURE__ */ new Date()
443
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
440
444
  });
441
445
  }
442
446
  await syncTotalStats(ctx);
@@ -533,8 +537,8 @@ ${debugInfo}`];
533
537
  remove: flags.remove || options.remove
534
538
  };
535
539
  logger.info(`合并后options: ${JSON.stringify(cleanedOptions, null, 2)}`);
536
- if ((cleanedOptions.query || cleanedOptions.remove) && (parsedKeywords.length > 0 || cleanedOptions.method !== void 0 || cleanedOptions.threshold !== void 0 || cleanedOptions.message !== void 0 || cleanedOptions.enableMessage || cleanedOptions.disableMessage || cleanedOptions.groupId !== void 0)) {
537
- return "参数冲突:-? 或 -r 不能与其他参数或关键词一起使用";
540
+ if ((cleanedOptions.query || cleanedOptions.remove) && (parsedKeywords.length > 0 || cleanedOptions.method !== void 0 || cleanedOptions.threshold !== void 0 || cleanedOptions.message !== void 0 || cleanedOptions.enableMessage || cleanedOptions.disableMessage)) {
541
+ return "参数冲突:-? 或 -r 不能与其他参数或关键词一起使用(仅可搭配 -i)";
538
542
  }
539
543
  const hasRealMessageParam = cleanedOptions.message !== void 0;
540
544
  const hasRealEnableMessageParam = cleanedOptions.enableMessage === true;
@@ -1103,7 +1107,7 @@ gvc -r # 删除配置`;
1103
1107
  autoApproved: totalAutoApproved,
1104
1108
  manuallyApproved: totalManuallyApproved,
1105
1109
  rejected: totalRejected,
1106
- lastUpdated: /* @__PURE__ */ new Date()
1110
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
1107
1111
  });
1108
1112
  logger.info(`总计统计已同步: 自动批准${totalAutoApproved}, 手动批准${totalManuallyApproved}, 拒绝${totalRejected}`);
1109
1113
  }
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.19",
4
+ "version": "1.0.20",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
package/readme.md CHANGED
@@ -48,6 +48,9 @@ group-verify.config -r
48
48
 
49
49
  # 指定群号配置
50
50
  group-verify.config -i 123456789 关键词1,关键词2 -m 1 -t 1
51
+
52
+ > **提示**: `-?`(查询)和 `-r`(删除)仍然与所有其它参数 / 关键字互斥,
53
+ > 但可以和 `-i` 组合使用,例如 `gvc -i 123 -?` 或 `gvc -i 123 -r`。这样便于在私聊环境下查询或删除指定群的设置。
51
54
  ```
52
55
 
53
56
  ### 审核命令
@@ -106,6 +109,12 @@ group-verify.stats total
106
109
  - `-nomsg` - 禁用提醒消息功能
107
110
  - 不带参数的 `-msg` 会显示帮助信息
108
111
 
112
+ ### 提醒消息变量
113
+
114
+ ### 其他注意事项
115
+
116
+ - 统计数据的 **最后更新时间** 使用完整的日期+时间存储,升级到最新版后若看到 `00:00:00`,请手动重建或清除旧的统计记录以便记录最新时间。
117
+
109
118
  ### 提醒消息变量
110
119
  ```
111
120
  {user} - 用户名
package/src/index.ts CHANGED
@@ -25,8 +25,8 @@ export interface GroupVerificationConfig {
25
25
  reminderMessage: string
26
26
  createdBy: string
27
27
  updatedBy: string
28
- createdAt: Date
29
- updatedAt: Date
28
+ createdAt: string | Date
29
+ updatedAt: string | Date
30
30
  }
31
31
 
32
32
  // 群组统计信息表
@@ -36,7 +36,7 @@ export interface GroupVerificationStats {
36
36
  autoApproved: number
37
37
  manuallyApproved: number
38
38
  rejected: number
39
- lastUpdated: Date
39
+ lastUpdated: string | Date
40
40
  }
41
41
 
42
42
  // 待审核申请表
@@ -46,7 +46,7 @@ export interface PendingVerification {
46
46
  userId: string
47
47
  userName: string
48
48
  requestMessage: string
49
- applyTime: Date
49
+ applyTime: string | Date
50
50
  }
51
51
 
52
52
  export interface Config {
@@ -417,8 +417,8 @@ export function apply(ctx: Context, config: Config) {
417
417
  reminderMessage: 'string',
418
418
  createdBy: 'string',
419
419
  updatedBy: 'string',
420
- createdAt: 'date',
421
- updatedAt: 'date'
420
+ createdAt: 'string',
421
+ updatedAt: 'string'
422
422
  }, {
423
423
  primary: 'id',
424
424
  autoInc: true
@@ -442,7 +442,9 @@ export function apply(ctx: Context, config: Config) {
442
442
  autoApproved: 'integer',
443
443
  manuallyApproved: 'integer',
444
444
  rejected: 'integer',
445
- lastUpdated: 'date'
445
+ // store as string (ISO timestamp) to preserve full date+time;
446
+ // Koishi `date` type truncates to day which leads to 00:00:00.
447
+ lastUpdated: 'string'
446
448
  }, {
447
449
  primary: 'id',
448
450
  autoInc: true
@@ -454,7 +456,8 @@ export function apply(ctx: Context, config: Config) {
454
456
  userId: 'string',
455
457
  userName: 'string',
456
458
  requestMessage: 'string',
457
- applyTime: 'date'
459
+ // record full timestamp as string to keep time component
460
+ applyTime: 'string'
458
461
  }, {
459
462
  primary: 'id',
460
463
  autoInc: true
@@ -546,12 +549,27 @@ export function apply(ctx: Context, config: Config) {
546
549
  })
547
550
 
548
551
  // 处理验证失败的情况
549
- async function handleFailedVerification(ctx: Context, session: any, config: GroupVerificationConfig) {
550
- const guildId = session.guildId
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();
551
562
  const userId = session.userId
552
563
  const username = session.username || '未知用户'
553
564
  const message = session.content || ''
554
-
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
+
555
573
  // 获取群信息
556
574
  let groupName = '未知群组'
557
575
  try {
@@ -560,30 +578,21 @@ export function apply(ctx: Context, config: Config) {
560
578
  } catch (error) {
561
579
  // 无法获取群名称时使用默认值
562
580
  }
563
-
564
- // 执行验证获取详细信息
565
- const { matchedCount, requiredThreshold } = await verifyApplication(config, message, session)
566
-
581
+
567
582
  // 将申请加入待审核列表
568
583
  await ctx.database.create('group_verification_pending', {
569
584
  groupId: guildId,
570
585
  userId: userId,
571
586
  userName: username,
572
587
  requestMessage: message,
573
- applyTime: new Date()
588
+ applyTime: new Date().toISOString()
574
589
  })
575
-
576
- // 如果 guildId 不合法,跳过
577
- if (!guildId) {
578
- logger.warn('handleFailedVerification 收到无效 guildId,已放弃发送')
579
- return
580
- }
581
590
  // 如果提醒消息被禁用,直接返回
582
591
  if (!config.reminderEnabled || !config.reminderMessage || config.reminderMessage === '') {
583
592
  logger.info(`群 ${guildId} 的提醒消息已被禁用,跳过发送`)
584
593
  return
585
594
  }
586
-
595
+
587
596
  // 替换提醒消息中的变量
588
597
  let reminderMsg = config.reminderMessage
589
598
  reminderMsg = reminderMsg
@@ -592,9 +601,9 @@ export function apply(ctx: Context, config: Config) {
592
601
  .replace(/{group}/g, guildId)
593
602
  .replace(/{gname}/g, groupName)
594
603
  .replace(/{question}/g, message)
595
- .replace(/{answer}/g, matchedCount.toString())
596
- .replace(/{threshold}/g, requiredThreshold)
597
-
604
+ .replace(/{answer}/g, matchedCount!.toString())
605
+ .replace(/{threshold}/g, requiredThreshold!)
606
+
598
607
  // 发送提醒消息到群内
599
608
  await ctx.broadcast([guildId], reminderMsg)
600
609
  }
@@ -609,7 +618,7 @@ export function apply(ctx: Context, config: Config) {
609
618
  const stats = existingStats[0]
610
619
  await ctx.database.set('group_verification_stats', { id: stats.id }, {
611
620
  [action]: stats[action] + 1,
612
- lastUpdated: new Date()
621
+ lastUpdated: new Date().toISOString()
613
622
  })
614
623
  } else {
615
624
  await ctx.database.create('group_verification_stats', {
@@ -617,7 +626,7 @@ export function apply(ctx: Context, config: Config) {
617
626
  autoApproved: action === 'autoApproved' ? 1 : 0,
618
627
  manuallyApproved: action === 'manuallyApproved' ? 1 : 0,
619
628
  rejected: action === 'rejected' ? 1 : 0,
620
- lastUpdated: new Date()
629
+ lastUpdated: new Date().toISOString()
621
630
  })
622
631
  }
623
632
 
@@ -755,11 +764,11 @@ export function apply(ctx: Context, config: Config) {
755
764
  }
756
765
  logger.info(`合并后options: ${JSON.stringify(cleanedOptions, null, 2)}`)
757
766
 
758
- // 检查 -? 和 -r 的独占性
767
+ // 检查 -? 和 -r 的独占性;允许与 -i 并存
759
768
  if ((cleanedOptions.query || cleanedOptions.remove) &&
760
769
  (parsedKeywords.length > 0 || cleanedOptions.method !== undefined || cleanedOptions.threshold !== undefined ||
761
- cleanedOptions.message !== undefined || cleanedOptions.enableMessage || cleanedOptions.disableMessage || cleanedOptions.groupId !== undefined)) {
762
- return '参数冲突:-? 或 -r 不能与其他参数或关键词一起使用'
770
+ cleanedOptions.message !== undefined || cleanedOptions.enableMessage || cleanedOptions.disableMessage)) {
771
+ return '参数冲突:-? 或 -r 不能与其他参数或关键词一起使用(仅可搭配 -i)'
763
772
  }
764
773
 
765
774
  // 检查消息参数冲突
@@ -1495,7 +1504,7 @@ gvc -r # 删除配置`
1495
1504
  autoApproved: totalAutoApproved,
1496
1505
  manuallyApproved: totalManuallyApproved,
1497
1506
  rejected: totalRejected,
1498
- lastUpdated: new Date()
1507
+ lastUpdated: new Date().toISOString()
1499
1508
  })
1500
1509
 
1501
1510
  logger.info(`总计统计已同步: 自动批准${totalAutoApproved}, 手动批准${totalManuallyApproved}, 拒绝${totalRejected}`)