koishi-plugin-group-verification 1.0.14 → 1.0.16
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 +2 -3
- package/lib/index.js +270 -70
- package/package.json +2 -2
- package/readme.md +29 -21
- package/src/index.ts +371 -95
- package/USAGE_EXAMPLE.md +0 -162
package/lib/index.d.ts
CHANGED
|
@@ -12,9 +12,7 @@ export interface GroupVerificationConfig {
|
|
|
12
12
|
groupId: string;
|
|
13
13
|
keywords: string[];
|
|
14
14
|
reviewMethod: 0 | 1 | 2 | 3;
|
|
15
|
-
reviewParameters:
|
|
16
|
-
threshold?: number;
|
|
17
|
-
};
|
|
15
|
+
reviewParameters: number;
|
|
18
16
|
reminderEnabled: boolean;
|
|
19
17
|
reminderMessage: string;
|
|
20
18
|
createdBy: string;
|
|
@@ -40,6 +38,7 @@ export interface PendingVerification {
|
|
|
40
38
|
}
|
|
41
39
|
export interface Config {
|
|
42
40
|
defaultReminderMessage?: string;
|
|
41
|
+
enableStrictGroupCheck?: boolean;
|
|
43
42
|
logLevel?: 'debug' | 'info' | 'warn' | 'error';
|
|
44
43
|
}
|
|
45
44
|
export declare const Config: Schema<Config>;
|
package/lib/index.js
CHANGED
|
@@ -29,14 +29,15 @@ module.exports = __toCommonJS(src_exports);
|
|
|
29
29
|
var import_koishi = require("koishi");
|
|
30
30
|
var name = "group-verification";
|
|
31
31
|
var Config = import_koishi.Schema.object({
|
|
32
|
-
defaultReminderMessage: import_koishi.Schema.string().default(
|
|
32
|
+
defaultReminderMessage: import_koishi.Schema.string().description("默认提醒消息模板").default(
|
|
33
33
|
`用户 {user}({id}) 申请加入群 {gname}({group})
|
|
34
34
|
申请理由:{question}
|
|
35
35
|
答对情况:{answer}
|
|
36
36
|
阈值要求:{threshold}
|
|
37
37
|
请管理员使用 #同意 或 #拒绝 来处理此申请`
|
|
38
|
-
)
|
|
39
|
-
|
|
38
|
+
),
|
|
39
|
+
enableStrictGroupCheck: import_koishi.Schema.boolean().description("是否启用严格的群号检查(验证机器人是否在群中)").default(true),
|
|
40
|
+
logLevel: import_koishi.Schema.union(["debug", "info", "warn", "error"]).description("日志级别").default("info")
|
|
40
41
|
}).description("群组验证插件配置");
|
|
41
42
|
var inject = ["database"];
|
|
42
43
|
function apply(ctx, config) {
|
|
@@ -45,7 +46,8 @@ function apply(ctx, config) {
|
|
|
45
46
|
groupId: "string",
|
|
46
47
|
keywords: "list",
|
|
47
48
|
reviewMethod: "integer",
|
|
48
|
-
reviewParameters: "
|
|
49
|
+
reviewParameters: "integer",
|
|
50
|
+
// 直接存储数字
|
|
49
51
|
reminderEnabled: "boolean",
|
|
50
52
|
reminderMessage: "string",
|
|
51
53
|
createdBy: "string",
|
|
@@ -156,14 +158,14 @@ function apply(ctx, config) {
|
|
|
156
158
|
requiredThreshold = "null";
|
|
157
159
|
break;
|
|
158
160
|
case 1:
|
|
159
|
-
isValid = matchedCount >= (config2.reviewParameters
|
|
160
|
-
requiredThreshold = `${config2.reviewParameters
|
|
161
|
+
isValid = matchedCount >= (config2.reviewParameters || 1);
|
|
162
|
+
requiredThreshold = `${config2.reviewParameters || 1}`;
|
|
161
163
|
break;
|
|
162
164
|
case 2:
|
|
163
165
|
const ratio = matchedCount / config2.keywords.length;
|
|
164
|
-
const requiredRatio = (config2.reviewParameters
|
|
166
|
+
const requiredRatio = (config2.reviewParameters || 100) / 100;
|
|
165
167
|
isValid = ratio >= requiredRatio;
|
|
166
|
-
requiredThreshold = `${config2.reviewParameters
|
|
168
|
+
requiredThreshold = `${config2.reviewParameters || 100}%`;
|
|
167
169
|
break;
|
|
168
170
|
case 3:
|
|
169
171
|
isValid = false;
|
|
@@ -265,23 +267,57 @@ ${debugInfo}`];
|
|
|
265
267
|
"group-verify.配置",
|
|
266
268
|
"gvc"
|
|
267
269
|
).option("groupId", "-i <groupId> 指定群号").option("method", "-m <method> 审核方式 (0-3)").option("threshold", "-t <threshold> 阈值参数").option("message", "-msg [message] 自定义提醒消息").option("disableMessage", "-nomsg 禁用提醒消息").option("query", "-? 查询当前配置").option("remove", "-r 删除配置").action(async ({ session, options }, keywords) => {
|
|
270
|
+
logger.info(`=== 命令解析调试 ===`);
|
|
271
|
+
logger.info(`原始keywords: "${keywords}" (类型: ${typeof keywords})`);
|
|
272
|
+
logger.info(`options对象: ${JSON.stringify(options, null, 2)}`);
|
|
273
|
+
logger.info(`session内容: guildId=${session.guildId}, userId=${session.userId}`);
|
|
274
|
+
logger.info(`==================`);
|
|
268
275
|
const targetGroupId = options.groupId || session.guildId;
|
|
269
|
-
const [hasPermission, errorMsg] = await checkPermission(session, targetGroupId);
|
|
270
|
-
if (!hasPermission) {
|
|
271
|
-
return errorMsg || "权限不足";
|
|
272
|
-
}
|
|
273
|
-
let groupName = "未知群组";
|
|
274
276
|
if (targetGroupId) {
|
|
275
277
|
try {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
+
if (config.enableStrictGroupCheck) {
|
|
279
|
+
await session.bot.getGuild(targetGroupId);
|
|
280
|
+
}
|
|
281
|
+
const [hasPermission, errorMsg] = await checkPermission(session, targetGroupId);
|
|
282
|
+
if (!hasPermission) {
|
|
283
|
+
return errorMsg || "权限不足";
|
|
284
|
+
}
|
|
278
285
|
} catch (error) {
|
|
286
|
+
if (config.enableStrictGroupCheck) {
|
|
287
|
+
return `群号 ${targetGroupId} 无效或机器人不在该群中`;
|
|
288
|
+
} else {
|
|
289
|
+
const [hasPermission, errorMsg] = await checkPermission(session, targetGroupId);
|
|
290
|
+
if (!hasPermission) {
|
|
291
|
+
return errorMsg || "权限不足";
|
|
292
|
+
}
|
|
293
|
+
}
|
|
279
294
|
}
|
|
295
|
+
} else {
|
|
296
|
+
return "请在群聊中使用此命令或指定群号(-i参数)";
|
|
297
|
+
}
|
|
298
|
+
if (options.message !== void 0 && options.disableMessage) {
|
|
299
|
+
return "参数冲突:不能同时使用 -msg 和 -nomsg";
|
|
300
|
+
}
|
|
301
|
+
const usedOptions = [];
|
|
302
|
+
if (options.method !== void 0) usedOptions.push("-m");
|
|
303
|
+
if (options.threshold !== void 0) usedOptions.push("-t");
|
|
304
|
+
if (options.groupId !== void 0) usedOptions.push("-i");
|
|
305
|
+
if (options.message !== void 0) usedOptions.push("-msg");
|
|
306
|
+
if (options.disableMessage) usedOptions.push("-nomsg");
|
|
307
|
+
if (usedOptions.length > new Set(usedOptions).size) {
|
|
308
|
+
return `检测到重复参数: ${usedOptions.join(", ")},将使用最后一次出现的值`;
|
|
309
|
+
}
|
|
310
|
+
let groupName = "未知群组";
|
|
311
|
+
try {
|
|
312
|
+
const guild = await session.bot.getGuild(targetGroupId);
|
|
313
|
+
groupName = guild.name || groupName;
|
|
314
|
+
} catch (error) {
|
|
280
315
|
}
|
|
281
316
|
if (options.remove) {
|
|
282
317
|
const existingConfig2 = await ctx.database.get("group_verification_config", { groupId: targetGroupId });
|
|
283
318
|
if (existingConfig2.length > 0) {
|
|
284
319
|
await ctx.database.remove("group_verification_config", { id: existingConfig2[0].id });
|
|
320
|
+
logger.info(`配置删除 - 用户ID:${session.userId}, 群号:${targetGroupId}`);
|
|
285
321
|
return `已删除群 ${targetGroupId} 的验证配置`;
|
|
286
322
|
} else {
|
|
287
323
|
return `群 ${targetGroupId} 无验证配置`;
|
|
@@ -291,31 +327,34 @@ ${debugInfo}`];
|
|
|
291
327
|
const existingConfig2 = await ctx.database.get("group_verification_config", { groupId: targetGroupId });
|
|
292
328
|
if (existingConfig2.length > 0) {
|
|
293
329
|
const config2 = existingConfig2[0];
|
|
330
|
+
const decodedKeywords2 = config2.keywords.map((keyword) => {
|
|
331
|
+
return keyword.replace(/\[\[COMMA\]\]/g, ",");
|
|
332
|
+
});
|
|
294
333
|
let methodDesc = "";
|
|
295
334
|
let thresholdInfo = "";
|
|
296
335
|
switch (config2.reviewMethod) {
|
|
297
336
|
case 0:
|
|
298
337
|
methodDesc = "全部同意";
|
|
299
|
-
thresholdInfo = "
|
|
338
|
+
thresholdInfo = "无";
|
|
300
339
|
break;
|
|
301
340
|
case 1:
|
|
302
341
|
methodDesc = `按数量同意`;
|
|
303
|
-
thresholdInfo =
|
|
342
|
+
thresholdInfo = config2.reviewParameters?.toString() || "无";
|
|
304
343
|
break;
|
|
305
344
|
case 2:
|
|
306
345
|
methodDesc = `按比例同意`;
|
|
307
|
-
thresholdInfo = `${config2.reviewParameters
|
|
346
|
+
thresholdInfo = config2.reviewParameters ? `${config2.reviewParameters}%` : "无";
|
|
308
347
|
break;
|
|
309
348
|
case 3:
|
|
310
349
|
methodDesc = "全部拒绝";
|
|
311
|
-
thresholdInfo = "
|
|
350
|
+
thresholdInfo = "无";
|
|
312
351
|
break;
|
|
313
352
|
}
|
|
314
353
|
const createTime = new Date(config2.createdAt).toLocaleString("zh-CN", { timeZone: "Asia/Shanghai" });
|
|
315
354
|
const updateTime = new Date(config2.updatedAt).toLocaleString("zh-CN", { timeZone: "Asia/Shanghai" });
|
|
316
355
|
const reminderStatus = config2.reminderEnabled ? "启用" : "禁用";
|
|
317
356
|
return `群 ${targetGroupId} 配置:
|
|
318
|
-
关键词: ${
|
|
357
|
+
关键词: ${decodedKeywords2.join(", ")}
|
|
319
358
|
审核方式: ${methodDesc}
|
|
320
359
|
阈值: ${thresholdInfo}
|
|
321
360
|
提醒消息: ${reminderStatus}
|
|
@@ -328,8 +367,92 @@ ${debugInfo}`];
|
|
|
328
367
|
return `群 ${targetGroupId} 无验证配置`;
|
|
329
368
|
}
|
|
330
369
|
}
|
|
331
|
-
let keywordList =
|
|
332
|
-
if (
|
|
370
|
+
let keywordList = [];
|
|
371
|
+
if (keywords) {
|
|
372
|
+
logger.info(`开始处理关键词: "${keywords}"`);
|
|
373
|
+
let processedInput = keywords.trim();
|
|
374
|
+
let keywordSection = processedInput;
|
|
375
|
+
let paramSection = "";
|
|
376
|
+
const paramMatch = processedInput.match(/\s+-(?:m|t|i|msg|nomsg|\?|r)\s+/);
|
|
377
|
+
if (paramMatch) {
|
|
378
|
+
const paramIndex = paramMatch.index;
|
|
379
|
+
keywordSection = processedInput.substring(0, paramIndex).trim();
|
|
380
|
+
paramSection = processedInput.substring(paramIndex).trim();
|
|
381
|
+
logger.info(`参数分离: 关键词="${keywordSection}", 参数="${paramSection}"`);
|
|
382
|
+
}
|
|
383
|
+
if (options.method !== void 0) {
|
|
384
|
+
logger.info(`检测到 -m 参数: ${options.method}`);
|
|
385
|
+
}
|
|
386
|
+
if (options.threshold !== void 0) {
|
|
387
|
+
logger.info(`检测到 -t 参数: ${options.threshold}`);
|
|
388
|
+
}
|
|
389
|
+
if (typeof paramSection !== "undefined" && paramSection) {
|
|
390
|
+
logger.info(`手动解析参数部分: "${paramSection}"`);
|
|
391
|
+
const mMatch = paramSection.match(/-m\s+(\d+)/);
|
|
392
|
+
if (mMatch && options.method === void 0) {
|
|
393
|
+
options.method = mMatch[1];
|
|
394
|
+
logger.info(`手动解析 -m: ${options.method}`);
|
|
395
|
+
}
|
|
396
|
+
const tMatch = paramSection.match(/-t\s+(\d+)/);
|
|
397
|
+
if (tMatch && options.threshold === void 0) {
|
|
398
|
+
options.threshold = tMatch[1];
|
|
399
|
+
logger.info(`手动解析 -t: ${options.threshold}`);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
if (keywordSection) {
|
|
403
|
+
logger.info(`开始处理关键词部分: "${keywordSection}"`);
|
|
404
|
+
const result = [];
|
|
405
|
+
let i = 0;
|
|
406
|
+
while (i < keywordSection.length) {
|
|
407
|
+
const char = keywordSection[i];
|
|
408
|
+
if (char === '"') {
|
|
409
|
+
i++;
|
|
410
|
+
let content = "";
|
|
411
|
+
let foundEndQuote = false;
|
|
412
|
+
while (i < keywordSection.length) {
|
|
413
|
+
if (keywordSection[i] === '"' && (i === 0 || keywordSection[i - 1] !== "\\")) {
|
|
414
|
+
foundEndQuote = true;
|
|
415
|
+
i++;
|
|
416
|
+
break;
|
|
417
|
+
} else {
|
|
418
|
+
content += keywordSection[i];
|
|
419
|
+
i++;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
let hasNextComma = false;
|
|
423
|
+
if (i < keywordSection.length && keywordSection[i] === ",") {
|
|
424
|
+
hasNextComma = true;
|
|
425
|
+
i++;
|
|
426
|
+
}
|
|
427
|
+
result.push(content);
|
|
428
|
+
logger.info(`引号处理: "${content}", 下一个逗号: ${hasNextComma}`);
|
|
429
|
+
if (!foundEndQuote) {
|
|
430
|
+
logger.info("未找到结束引号,前引号作为内容处理");
|
|
431
|
+
}
|
|
432
|
+
} else if (char === "," || char === " ") {
|
|
433
|
+
i++;
|
|
434
|
+
} else {
|
|
435
|
+
let content = "";
|
|
436
|
+
while (i < keywordSection.length && keywordSection[i] !== "," && keywordSection[i] !== " ") {
|
|
437
|
+
content += keywordSection[i];
|
|
438
|
+
i++;
|
|
439
|
+
}
|
|
440
|
+
if (content) {
|
|
441
|
+
result.push(content);
|
|
442
|
+
logger.info(`普通内容处理: "${content}"`);
|
|
443
|
+
}
|
|
444
|
+
if (i < keywordSection.length && (keywordSection[i] === "," || keywordSection[i] === " ")) {
|
|
445
|
+
i++;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
keywordList = result.filter((item) => item.length > 0);
|
|
450
|
+
logger.info(`最终处理结果: [${keywordList.map((k) => `"${k}"`).join(", ")}]`);
|
|
451
|
+
}
|
|
452
|
+
logger.info(`最终关键词列表: [${keywordList.map((k) => `"${k}"`).join(", ")}]`);
|
|
453
|
+
}
|
|
454
|
+
logger.info(`关键词解析结果: [${keywordList.join(", ")}] - 原始输入: "${keywords}"`);
|
|
455
|
+
if (keywordList.length === 0 && !options.query && !options.remove) {
|
|
333
456
|
const hasConfigParams = options.method !== void 0 || options.threshold !== void 0 || options.message !== void 0 || options.disableMessage !== void 0;
|
|
334
457
|
if (!hasConfigParams) {
|
|
335
458
|
return `用法:
|
|
@@ -357,28 +480,25 @@ gvc -r # 删除配置`;
|
|
|
357
480
|
reminderMessage = "";
|
|
358
481
|
} else if (options.message !== void 0) {
|
|
359
482
|
reminderEnabled = true;
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
阈值要求:{threshold}
|
|
364
|
-
请管理员使用 #同意 或 #拒绝 来处理此申请`;
|
|
483
|
+
if (options.message !== "") {
|
|
484
|
+
reminderMessage = options.message;
|
|
485
|
+
}
|
|
365
486
|
}
|
|
366
487
|
if (reminderEnabled && reminderMessage) {
|
|
367
488
|
reminderMessage = reminderMessage.replace(/\\n/g, "\n");
|
|
368
489
|
}
|
|
369
490
|
let reviewMethod = 0;
|
|
370
|
-
let reviewParameters =
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
}
|
|
491
|
+
let reviewParameters = 0;
|
|
492
|
+
let existingConfig = null;
|
|
493
|
+
const configs = await ctx.database.get("group_verification_config", { groupId: targetGroupId });
|
|
494
|
+
if (configs.length > 0) {
|
|
495
|
+
existingConfig = configs[0];
|
|
496
|
+
reviewMethod = existingConfig.reviewMethod;
|
|
497
|
+
if (existingConfig.reviewParameters === void 0 || existingConfig.reviewParameters === null || isNaN(existingConfig.reviewParameters)) {
|
|
498
|
+
reviewParameters = 0;
|
|
499
|
+
logger.info(`检测到老版本数据或无效值,使用默认阈值: 0`);
|
|
500
|
+
} else {
|
|
501
|
+
reviewParameters = existingConfig.reviewParameters;
|
|
382
502
|
}
|
|
383
503
|
}
|
|
384
504
|
if (options.method !== void 0) {
|
|
@@ -387,48 +507,115 @@ gvc -r # 删除配置`;
|
|
|
387
507
|
return "审核方式参数错误:0-全部同意, 1-按数量同意, 2-按比例同意, 3-全部拒绝";
|
|
388
508
|
}
|
|
389
509
|
reviewMethod = methodNum;
|
|
510
|
+
logger.info(`审核方式明确指定为: ${reviewMethod}`);
|
|
511
|
+
if (reviewMethod === 0 || reviewMethod === 3) {
|
|
512
|
+
reviewParameters = 0;
|
|
513
|
+
} else if (reviewParameters === 0) {
|
|
514
|
+
reviewParameters = reviewMethod === 1 ? keywordList.length : 100;
|
|
515
|
+
}
|
|
516
|
+
} else {
|
|
517
|
+
logger.info(`未指定审核方式,保持原有值: ${reviewMethod}`);
|
|
390
518
|
}
|
|
391
|
-
if (
|
|
519
|
+
if (options.threshold !== void 0) {
|
|
392
520
|
const thresholdNum = parseInt(options.threshold);
|
|
393
521
|
if (isNaN(thresholdNum)) {
|
|
394
522
|
return "阈值参数必须为数字";
|
|
395
523
|
}
|
|
396
524
|
if (reviewMethod === 1) {
|
|
397
|
-
if (thresholdNum
|
|
398
|
-
return `数量阈值必须在
|
|
525
|
+
if (thresholdNum < 0 || thresholdNum > keywordList.length) {
|
|
526
|
+
return `数量阈值必须在0-${keywordList.length}之间(0表示全部同意)`;
|
|
399
527
|
}
|
|
400
|
-
reviewParameters
|
|
528
|
+
reviewParameters = thresholdNum;
|
|
529
|
+
logger.info(`明确指定阈值: ${thresholdNum}`);
|
|
401
530
|
} else if (reviewMethod === 2) {
|
|
402
|
-
if (thresholdNum
|
|
403
|
-
return "比例阈值必须在
|
|
531
|
+
if (thresholdNum < 0 || thresholdNum > 100) {
|
|
532
|
+
return "比例阈值必须在0-100之间(0表示全部同意)";
|
|
404
533
|
}
|
|
405
|
-
reviewParameters
|
|
534
|
+
reviewParameters = thresholdNum;
|
|
535
|
+
logger.info(`明确指定阈值: ${thresholdNum}%`);
|
|
536
|
+
}
|
|
537
|
+
} else if (existingConfig && reviewMethod === 1 && reviewParameters !== 0) {
|
|
538
|
+
const oldKeywordCount = existingConfig.keywords.length;
|
|
539
|
+
const newKeywordCount = keywordList.length;
|
|
540
|
+
if (oldKeywordCount !== newKeywordCount) {
|
|
541
|
+
reviewParameters = newKeywordCount;
|
|
542
|
+
logger.info(`关键词数量从${oldKeywordCount}变为${newKeywordCount},自动调整阈值`);
|
|
543
|
+
await ctx.database.set("group_verification_config", { id: existingConfig.id }, {
|
|
544
|
+
reviewParameters,
|
|
545
|
+
updatedBy: session.username || session.userId,
|
|
546
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
547
|
+
});
|
|
548
|
+
logger.info(`已更新数据库阈值为: ${reviewParameters}`);
|
|
549
|
+
} else {
|
|
550
|
+
logger.info(`关键词数量未变化(${newKeywordCount}),保持原阈值: ${reviewParameters}`);
|
|
406
551
|
}
|
|
407
552
|
}
|
|
408
|
-
const
|
|
409
|
-
const
|
|
410
|
-
|
|
553
|
+
const existingConfigs = await ctx.database.get("group_verification_config", { groupId: targetGroupId });
|
|
554
|
+
const encodedKeywords = keywordList.map((keyword) => {
|
|
555
|
+
return keyword.replace(/,/g, "[[COMMA]]");
|
|
556
|
+
});
|
|
557
|
+
logger.info(`编码后准备存储的关键词: ${JSON.stringify(encodedKeywords)}`);
|
|
558
|
+
const dbData = {
|
|
559
|
+
keywords: encodedKeywords,
|
|
411
560
|
reviewMethod,
|
|
412
561
|
reviewParameters,
|
|
562
|
+
// 直接存储数字
|
|
413
563
|
reminderEnabled,
|
|
414
564
|
reminderMessage,
|
|
415
565
|
updatedBy: session.username || session.userId,
|
|
416
566
|
updatedAt: /* @__PURE__ */ new Date()
|
|
417
567
|
};
|
|
418
|
-
if (
|
|
419
|
-
await ctx.database.set("group_verification_config", { id:
|
|
420
|
-
logger.info(
|
|
421
|
-
return `已更新群 ${targetGroupId} 的验证配置`;
|
|
568
|
+
if (existingConfigs.length > 0) {
|
|
569
|
+
await ctx.database.set("group_verification_config", { id: existingConfigs[0].id }, dbData);
|
|
570
|
+
logger.info(`更新配置成功 - 审核方式: ${reviewMethod}, 阈值: ${reviewParameters}`);
|
|
422
571
|
} else {
|
|
423
572
|
await ctx.database.create("group_verification_config", {
|
|
424
|
-
...configData,
|
|
425
573
|
groupId: targetGroupId,
|
|
574
|
+
...dbData,
|
|
426
575
|
createdBy: session.username || session.userId,
|
|
427
576
|
createdAt: /* @__PURE__ */ new Date()
|
|
428
577
|
});
|
|
429
|
-
logger.info(
|
|
430
|
-
return `已为群 ${targetGroupId} 创建验证配置`;
|
|
578
|
+
logger.info(`创建配置成功 - 审核方式: ${reviewMethod}, 阈值: ${reviewParameters}`);
|
|
431
579
|
}
|
|
580
|
+
const decodedKeywords = keywordList;
|
|
581
|
+
let feedbackMessage = `群 ${targetGroupId} 配置已更新:
|
|
582
|
+
`;
|
|
583
|
+
feedbackMessage += `关键词: ${decodedKeywords.map((k) => `"${k}"`).join(", ")}
|
|
584
|
+
`;
|
|
585
|
+
const methodMap = { 0: "全部同意", 1: "按数量", 2: "按比例", 3: "全部拒绝" };
|
|
586
|
+
feedbackMessage += `审核方式: ${methodMap[reviewMethod]}
|
|
587
|
+
`;
|
|
588
|
+
if (reviewParameters !== 0) {
|
|
589
|
+
const thresholdDisplay = reviewMethod === 2 ? `${reviewParameters}%` : reviewParameters.toString();
|
|
590
|
+
feedbackMessage += `阈值: ${thresholdDisplay}
|
|
591
|
+
`;
|
|
592
|
+
}
|
|
593
|
+
feedbackMessage += `提醒状态: ${reminderEnabled ? "启用" : "禁用"}
|
|
594
|
+
`;
|
|
595
|
+
if (reminderMessage && reminderEnabled) {
|
|
596
|
+
feedbackMessage += `提醒消息: ${reminderMessage.substring(0, 30)}${reminderMessage.length > 30 ? "..." : ""}
|
|
597
|
+
`;
|
|
598
|
+
}
|
|
599
|
+
if (existingConfig && reviewMethod === 1 && keywordList.length !== existingConfig.keywords.length) {
|
|
600
|
+
feedbackMessage += `⚠️ 关键词数量从${existingConfig.keywords.length}变为${keywordList.length},阈值已自动调整为${keywordList.length}
|
|
601
|
+
`;
|
|
602
|
+
}
|
|
603
|
+
logger.info(`准备存储到数据库的关键词: ${JSON.stringify(encodedKeywords)}`);
|
|
604
|
+
logger.info(`=== 配置处理详情 ===`);
|
|
605
|
+
logger.info(`原始输入: ${keywords || "无关键词"}`);
|
|
606
|
+
logger.info(`审核方式: ${reviewMethod} (${["全部同意", "按数量", "按比例", "全部拒绝"][reviewMethod]})`);
|
|
607
|
+
logger.info(`阈值参数: ${JSON.stringify(reviewParameters)}`);
|
|
608
|
+
logger.info(`关键词列表: [${keywordList.map((k) => `"${k}"`).join(", ")}]`);
|
|
609
|
+
logger.info(`现有配置: ${existingConfig ? "存在" : "不存在"}`);
|
|
610
|
+
if (existingConfig) {
|
|
611
|
+
logger.info(`原审核方式: ${existingConfig.reviewMethod}`);
|
|
612
|
+
logger.info(`原阈值: ${JSON.stringify(existingConfig.reviewParameters)}`);
|
|
613
|
+
logger.info(`原关键词数: ${existingConfig.keywords.length}`);
|
|
614
|
+
logger.info(`新关键词数: ${keywordList.length}`);
|
|
615
|
+
}
|
|
616
|
+
logger.info(`==================`);
|
|
617
|
+
logger.info(feedbackMessage.replace(/\n/g, "; "));
|
|
618
|
+
return feedbackMessage;
|
|
432
619
|
});
|
|
433
620
|
groupVerify.subcommand(".approve [userId]", "同意加群申请").alias(
|
|
434
621
|
"gv.accept",
|
|
@@ -639,25 +826,38 @@ gvc -r # 删除配置`;
|
|
|
639
826
|
参数说明:
|
|
640
827
|
-i <群号> 指定群号(私聊时必需)
|
|
641
828
|
-m <方式> 审核方式 (0=全部同意, 1=按数量, 2=按比例, 3=全部拒绝)
|
|
642
|
-
-t <阈值> 阈值参数(方式1
|
|
643
|
-
-msg [消息]
|
|
829
|
+
-t <阈值> 阈值参数(方式1:0-关键词数, 方式2:0-100)
|
|
830
|
+
-msg [消息] 自定义提醒消息(支持引号和\\n换行)
|
|
644
831
|
-nomsg 禁用提醒消息
|
|
645
832
|
-? 查询当前配置
|
|
646
833
|
-r 删除配置
|
|
647
834
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
835
|
+
引号使用规则:
|
|
836
|
+
• 关键词包含空格:gv.cfg "关键词1,关键词 2,关键词3"
|
|
837
|
+
• 提醒消息包含空格:gv.cfg -msg "这是包含空格的消息"
|
|
838
|
+
• 内部引号转义:gv.cfg -msg "包含\\"引号\\"的内容"
|
|
839
|
+
• 换行符:gv.cfg -msg "第一行\\n第二行"
|
|
840
|
+
|
|
841
|
+
特殊说明:
|
|
842
|
+
• 阈值可设为0表示全部同意
|
|
843
|
+
• 关键词数量变化时阈值会自动调整
|
|
844
|
+
• 重复参数会使用最后出现的值并提醒
|
|
845
|
+
• 群号检查可在插件配置中开关
|
|
846
|
+
|
|
847
|
+
提醒消息变量:
|
|
848
|
+
{user} - 用户名
|
|
849
|
+
{id} - 用户ID
|
|
850
|
+
{group} - 群号
|
|
851
|
+
{gname} - 群名称
|
|
852
|
+
{question} - 申请理由
|
|
853
|
+
{answer} - 答对数量/比例
|
|
854
|
+
{threshold} - 阈值要求
|
|
656
855
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
856
|
+
使用示例:
|
|
857
|
+
gv.cfg "关键词1,关键词2" -m 1 -t 2
|
|
858
|
+
gv.cfg -msg "用户 {user}\\n申请理由:{question}"
|
|
859
|
+
gv.cfg -m 2 -t 80
|
|
860
|
+
gv.cfg -nomsg
|
|
661
861
|
|
|
662
862
|
快捷命令:
|
|
663
863
|
gvc - 配置命令快捷方式
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-group-verification",
|
|
3
|
-
"description": "Koishi
|
|
4
|
-
"version": "1.0.
|
|
3
|
+
"description": "[WIP] Koishi 群组加群验证插件,支持多关键词匹配审核、多种审核方式和详细统计功能(开发中)",
|
|
4
|
+
"version": "1.0.16",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
7
7
|
"files": [
|
package/readme.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Koishi 群组验证插件
|
|
1
|
+
# Koishi 群组验证插件 [WIP]
|
|
2
2
|
|
|
3
3
|
一个功能完整的 Koishi 群组加群验证插件,支持多关键词匹配审核、多种审核方式和详细统计功能。
|
|
4
4
|
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
## 🚀 安装使用
|
|
15
15
|
|
|
16
|
-
```
|
|
16
|
+
```
|
|
17
17
|
# 在 Koishi 控制台中搜索并安装
|
|
18
18
|
koishi-plugin-group-verification
|
|
19
19
|
```
|
|
@@ -21,62 +21,70 @@ koishi-plugin-group-verification
|
|
|
21
21
|
## 📋 命令说明
|
|
22
22
|
|
|
23
23
|
### 主指令别名
|
|
24
|
-
- `group-verify` (
|
|
25
|
-
- `gv` (
|
|
26
|
-
- `gverify` (
|
|
24
|
+
- `group-verify` (完整英文名称)
|
|
25
|
+
- `gv` (英文快捷别名)
|
|
26
|
+
- `gverify` (英文中等长度别名)
|
|
27
27
|
|
|
28
28
|
### 配置命令
|
|
29
29
|
```
|
|
30
|
-
#
|
|
31
|
-
|
|
30
|
+
# 创建新配置(支持引号和逗号组合)
|
|
31
|
+
group-verify.config "关键词1,关键词2",关键词3 -m 1 -t 2
|
|
32
|
+
# 别名:gv.cfg gverify.cfg group-verify.cfg gv.配置 gverify.配置 group-verify.配置 gvc
|
|
32
33
|
|
|
33
34
|
# 修改审核参数
|
|
34
|
-
|
|
35
|
+
group-verify.config -m 2 -t 60
|
|
35
36
|
|
|
36
37
|
# 启用自定义提醒消息
|
|
37
|
-
|
|
38
|
+
group-verify.config -msg "用户 {user} 申请入群,匹配 {answer} 个关键词"
|
|
38
39
|
|
|
39
40
|
# 禁用提醒消息
|
|
40
|
-
|
|
41
|
+
group-verify.config -nomsg
|
|
41
42
|
|
|
42
43
|
# 查询当前配置
|
|
43
|
-
|
|
44
|
+
group-verify.config -?
|
|
44
45
|
|
|
45
46
|
# 删除配置
|
|
46
|
-
|
|
47
|
+
group-verify.config -r
|
|
48
|
+
|
|
49
|
+
# 指定群号配置
|
|
50
|
+
group-verify.config -i 123456789 关键词1,关键词2 -m 1 -t 1
|
|
47
51
|
```
|
|
48
52
|
|
|
49
53
|
### 审核命令
|
|
50
54
|
```
|
|
51
55
|
# 同意申请(处理最近一个)
|
|
52
|
-
|
|
56
|
+
group-verify.approve
|
|
57
|
+
# 别名:gv.accept gverify.accept group-verify.accept gv.同意 gverify.同意 group-verify.同意 gva
|
|
53
58
|
|
|
54
59
|
# 同意指定用户
|
|
55
|
-
|
|
60
|
+
group-verify.approve 123456789
|
|
56
61
|
|
|
57
62
|
# 同意所有申请
|
|
58
|
-
|
|
63
|
+
group-verify.approve all
|
|
59
64
|
|
|
60
65
|
# 拒绝申请
|
|
61
|
-
|
|
66
|
+
group-verify.reject 123456789
|
|
67
|
+
# 别名:gv.reject gverify.reject group-verify.reject gv.拒绝 gverify.拒绝 group-verify.拒绝 gvr
|
|
62
68
|
|
|
63
69
|
# 拒绝所有申请
|
|
64
|
-
|
|
70
|
+
group-verify.reject all
|
|
65
71
|
```
|
|
66
72
|
|
|
67
73
|
### 查询命令
|
|
68
74
|
```
|
|
69
75
|
# 查看待审核列表
|
|
70
|
-
|
|
76
|
+
group-verify.pending
|
|
77
|
+
# 别名:gv.list gverify.list group-verify.list gv.待审 gverify.待审 group-verify.待审 gvp
|
|
71
78
|
|
|
72
79
|
# 查看统计信息
|
|
73
|
-
|
|
80
|
+
group-verify.stats
|
|
81
|
+
# 别名:gv.stats gverify.stats group-verify.stats gv.统计 gverify.统计 group-verify.统计 gvs
|
|
74
82
|
|
|
75
83
|
# 查看指定群统计
|
|
76
|
-
|
|
84
|
+
group-verify.stats 123456789
|
|
77
85
|
|
|
78
86
|
# 查看总计统计(需要权限)
|
|
79
|
-
|
|
87
|
+
group-verify.stats total
|
|
80
88
|
```
|
|
81
89
|
|
|
82
90
|
## ⚙️ 参数说明
|