koishi-plugin-group-verification 1.0.34 → 1.0.35
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.js +38 -36
- package/package.json +3 -3
- package/readme.md +2 -2
- package/src/index.ts +2155 -2146
package/lib/index.js
CHANGED
|
@@ -45,7 +45,7 @@ var import_koishi = require("koishi");
|
|
|
45
45
|
var name = "group-verification";
|
|
46
46
|
var logger = console;
|
|
47
47
|
var Config = import_koishi.Schema.object({
|
|
48
|
-
defaultReminderMessage: import_koishi.Schema.string().description("默认提醒消息模板(使用 \\n 表示换行,可包含下方变量)").default("{user}({id})
|
|
48
|
+
defaultReminderMessage: import_koishi.Schema.string().description("默认提醒消息模板(使用 \\n 表示换行,可包含下方变量)").default("{user}({id}) 申请入群\\n申请理由: {question}\\n匹配情况: {answer}/{threshold}\\n使用 gva 同意或 gvr 拒绝申请"),
|
|
49
49
|
enableStrictGroupCheck: import_koishi.Schema.boolean().description("是否启用严格的群号检查(检查群号长度)").default(false),
|
|
50
50
|
logLevel: import_koishi.Schema.union(["debug", "info", "warn", "error"]).description("日志级别").default("info"),
|
|
51
51
|
permissionDeniedMessage: import_koishi.Schema.string().description("权限不足时返回给调用者的提示").default("权限不足: 需要群主/管理员权限或koishi三级以上权限"),
|
|
@@ -194,7 +194,7 @@ function usageString() {
|
|
|
194
194
|
__name(usageString, "usageString");
|
|
195
195
|
function mergeReminder(existingConfig, cleanedOptions, hasRealMessageParam, hasRealEnableMessageParam, hasRealDisableMessageParam, logger2, defaultMessage) {
|
|
196
196
|
let reminderEnabled = true;
|
|
197
|
-
let reminderMessage = defaultMessage || "{user}({id})
|
|
197
|
+
let reminderMessage = defaultMessage || "{user}({id}) 申请入群\\n申请理由: {question}\\n匹配情况: {answer}/{threshold}\\n使用 gva 同意或 gvr 拒绝申请";
|
|
198
198
|
if (existingConfig) {
|
|
199
199
|
reminderEnabled = existingConfig.reminderEnabled;
|
|
200
200
|
reminderMessage = existingConfig.reminderMessage || reminderMessage;
|
|
@@ -208,7 +208,7 @@ function mergeReminder(existingConfig, cleanedOptions, hasRealMessageParam, hasR
|
|
|
208
208
|
} else if (hasRealMessageParam) {
|
|
209
209
|
reminderEnabled = true;
|
|
210
210
|
if (cleanedOptions.message !== void 0) {
|
|
211
|
-
reminderMessage = cleanedOptions.message
|
|
211
|
+
reminderMessage = cleanedOptions.message;
|
|
212
212
|
logger2.debug(`设置自定义提醒消息: ${reminderMessage.substring(0, 50)}...`);
|
|
213
213
|
}
|
|
214
214
|
}
|
|
@@ -359,17 +359,17 @@ async function checkPermission(session, targetGroupId) {
|
|
|
359
359
|
}
|
|
360
360
|
try {
|
|
361
361
|
const member = await session.bot.getGuildMember(groupId, session.userId);
|
|
362
|
-
logger.
|
|
362
|
+
logger.debug(`权限检查 - 获取到成员信息:`, {
|
|
363
363
|
roles: member?.roles,
|
|
364
364
|
permissions: member?.permissions
|
|
365
365
|
});
|
|
366
366
|
if (member) {
|
|
367
367
|
if (member.permissions?.includes("OWNER") || member.roles?.includes("owner")) {
|
|
368
|
-
logger.
|
|
368
|
+
logger.debug(`权限检查 - 用户是群主`);
|
|
369
369
|
return [true];
|
|
370
370
|
}
|
|
371
371
|
if (member.roles?.includes("admin") || member.permissions?.includes("ADMINISTRATOR")) {
|
|
372
|
-
logger.
|
|
372
|
+
logger.debug(`权限检查 - 用户是管理员`);
|
|
373
373
|
return [true];
|
|
374
374
|
}
|
|
375
375
|
}
|
|
@@ -461,7 +461,7 @@ function parseConfigArgs(raw) {
|
|
|
461
461
|
}
|
|
462
462
|
}
|
|
463
463
|
tokens = tokens.map(
|
|
464
|
-
(t) => t.replace(new RegExp(ESC_QUOTE, "g"), '"').replace(new RegExp(ESC_BACKSLASH, "g"), "
|
|
464
|
+
(t) => t.replace(new RegExp(ESC_QUOTE, "g"), '"').replace(new RegExp(ESC_BACKSLASH, "g"), "\\\\")
|
|
465
465
|
);
|
|
466
466
|
for (let i = 0; i < tokens.length; i++) {
|
|
467
467
|
const tok = tokens[i];
|
|
@@ -606,7 +606,7 @@ async function handleFailedVerification(ctx, session, config, matchedCount, requ
|
|
|
606
606
|
logger.debug(`群 ${guildId} 的提醒消息已被禁用,跳过发送`);
|
|
607
607
|
return;
|
|
608
608
|
}
|
|
609
|
-
let reminderMsg = config.reminderMessage;
|
|
609
|
+
let reminderMsg = config.reminderMessage.replace(/\\\\n/g, "").replace(/\\n/g, "\n").replace(/\x01/g, "\\n");
|
|
610
610
|
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);
|
|
611
611
|
const rawChannel = (session.channelId || "").toString().trim();
|
|
612
612
|
const channel = rawChannel || guildId;
|
|
@@ -616,7 +616,7 @@ async function handleFailedVerification(ctx, session, config, matchedCount, requ
|
|
|
616
616
|
try {
|
|
617
617
|
await session.bot.broadcast([target], reminderMsg);
|
|
618
618
|
} catch (err) {
|
|
619
|
-
logger.warn("bot.broadcast
|
|
619
|
+
logger.warn("bot.broadcast 失败,回退到 ctx.broadcast", err);
|
|
620
620
|
if (typeof ctx.broadcast === "function") {
|
|
621
621
|
await ctx.broadcast([target], reminderMsg);
|
|
622
622
|
} else {
|
|
@@ -875,8 +875,8 @@ function apply(ctx, config) {
|
|
|
875
875
|
manuallyApproved: "integer",
|
|
876
876
|
rejected: "integer",
|
|
877
877
|
totalJoined: "integer",
|
|
878
|
-
//
|
|
879
|
-
// Koishi
|
|
878
|
+
// 以字符串(ISO 时间戳)格式存储,保留完整日期+时间;
|
|
879
|
+
// Koishi 的 date 类型会截断到天,导致时间显示为 00:00:00。
|
|
880
880
|
lastUpdated: "string"
|
|
881
881
|
}, {
|
|
882
882
|
primary: "id",
|
|
@@ -890,7 +890,7 @@ function apply(ctx, config) {
|
|
|
890
890
|
requestMessage: "string",
|
|
891
891
|
// 保存 OneBot 事件提供的原始 requestId;用于同意/拒绝操作
|
|
892
892
|
requestId: "string",
|
|
893
|
-
//
|
|
893
|
+
// 以字符串格式记录完整时间戳,保留时间分量
|
|
894
894
|
applyTime: "string"
|
|
895
895
|
}, {
|
|
896
896
|
primary: "id",
|
|
@@ -906,7 +906,7 @@ function apply(ctx, config) {
|
|
|
906
906
|
indexes: [["groupId"]]
|
|
907
907
|
});
|
|
908
908
|
ctx.on("guild-member-request", async (session) => {
|
|
909
|
-
logger.
|
|
909
|
+
logger.debug("收到 guild-member-request 事件,转发给处理函数");
|
|
910
910
|
await handleGuildMemberRequestEvent(ctx, session);
|
|
911
911
|
});
|
|
912
912
|
ctx.on("guild-member-added", async (session) => {
|
|
@@ -979,7 +979,7 @@ function apply(ctx, config) {
|
|
|
979
979
|
});
|
|
980
980
|
if (member) {
|
|
981
981
|
if (member.permissions?.includes("OWNER") || member.roles?.includes("owner")) {
|
|
982
|
-
logger.
|
|
982
|
+
logger.debug(`权限检查 - 用户是群主`);
|
|
983
983
|
return [true];
|
|
984
984
|
}
|
|
985
985
|
if (member.roles?.includes("admin") || member.permissions?.includes("ADMINISTRATOR")) {
|
|
@@ -1007,16 +1007,16 @@ ${debugInfo}`];
|
|
|
1007
1007
|
"group-verify.配置",
|
|
1008
1008
|
"gvc"
|
|
1009
1009
|
).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) => {
|
|
1010
|
-
logger.
|
|
1011
|
-
logger.
|
|
1010
|
+
logger.debug(`=== 命令解析调试 ===`);
|
|
1011
|
+
logger.debug(`session内容: guildId=${session.guildId}, userId=${session.userId}`);
|
|
1012
1012
|
const rawInput = session.content.split(/\s+/).slice(1).join(" ");
|
|
1013
|
-
logger.
|
|
1013
|
+
logger.debug(`原始命令参数: "${rawInput}"`);
|
|
1014
1014
|
const parsed = parseConfigArgs(rawInput);
|
|
1015
1015
|
const { keywords: parsedKeywords, flags, error: parseError } = parsed;
|
|
1016
1016
|
if (parseError) {
|
|
1017
1017
|
return parseError;
|
|
1018
1018
|
}
|
|
1019
|
-
logger.
|
|
1019
|
+
logger.debug(`解析结果 flags=${JSON.stringify(flags)}, keywords=[${parsedKeywords.join(", ")}]`);
|
|
1020
1020
|
const cleanedOptions = {
|
|
1021
1021
|
groupId: flags.groupId || options.groupId,
|
|
1022
1022
|
method: flags.method || (options.method === "" ? void 0 : options.method),
|
|
@@ -1028,7 +1028,7 @@ ${debugInfo}`];
|
|
|
1028
1028
|
query: flags.query || options.query,
|
|
1029
1029
|
remove: flags.remove || options.remove
|
|
1030
1030
|
};
|
|
1031
|
-
logger.
|
|
1031
|
+
logger.debug(`合并后options: ${JSON.stringify(cleanedOptions, null, 2)}`);
|
|
1032
1032
|
if ((cleanedOptions.query || cleanedOptions.remove) && (parsedKeywords.length > 0 || cleanedOptions.method !== void 0 || cleanedOptions.threshold !== void 0 || cleanedOptions.message !== void 0 || cleanedOptions.enableMessage || cleanedOptions.disableMessage)) {
|
|
1033
1033
|
return config.parameterConflictMessage || "参数冲突: -? 或 -r 不能与其他参数或关键词一起使用(仅可搭配 -i)";
|
|
1034
1034
|
}
|
|
@@ -1113,13 +1113,14 @@ ${debugInfo}`];
|
|
|
1113
1113
|
const createTime = new Date(config2.createdAt).toLocaleString("zh-CN", { timeZone: "Asia/Shanghai" });
|
|
1114
1114
|
const updateTime = new Date(config2.updatedAt).toLocaleString("zh-CN", { timeZone: "Asia/Shanghai" });
|
|
1115
1115
|
const reminderStatus = config2.reminderEnabled ? "启用" : "禁用";
|
|
1116
|
+
const displayMsg = (config2.reminderMessage || "无").replace(/\\\\n/g, "").replace(/\\n/g, "\n").replace(/\x01/g, "\\n");
|
|
1116
1117
|
return `群 ${targetGroupId} 配置:
|
|
1117
1118
|
关键词: ${decodedKeywords2.join(", ")}
|
|
1118
1119
|
审核方式: ${methodDesc}
|
|
1119
1120
|
阈值: ${thresholdInfo}
|
|
1120
1121
|
提醒消息: ${reminderStatus}
|
|
1121
1122
|
自定义消息:
|
|
1122
|
-
${
|
|
1123
|
+
${displayMsg}
|
|
1123
1124
|
创建时间: ${createTime}
|
|
1124
1125
|
更新时间: ${updateTime}
|
|
1125
1126
|
创建者: ${config2.createdBy}
|
|
@@ -1129,7 +1130,7 @@ ${config2.reminderMessage || "无"}
|
|
|
1129
1130
|
}
|
|
1130
1131
|
}
|
|
1131
1132
|
let keywordList = parsedKeywords.slice();
|
|
1132
|
-
logger.
|
|
1133
|
+
logger.debug(`关键词解析结果: [${keywordList.join(", ")}] - 原始输入: "${rawInput}"`);
|
|
1133
1134
|
if (keywordList.length === 0 && !cleanedOptions.query && !cleanedOptions.remove) {
|
|
1134
1135
|
const hasConfigParams = cleanedOptions.method !== void 0 || cleanedOptions.threshold !== void 0 || hasRealMessageParam || hasRealEnableMessageParam || hasRealDisableMessageParam;
|
|
1135
1136
|
if (!hasConfigParams) {
|
|
@@ -1162,7 +1163,7 @@ ${config2.reminderMessage || "无"}
|
|
|
1162
1163
|
reviewMethod = existingConfig.reviewMethod;
|
|
1163
1164
|
if (existingConfig.reviewParameters === void 0 || existingConfig.reviewParameters === null || isNaN(existingConfig.reviewParameters)) {
|
|
1164
1165
|
reviewParameters = 0;
|
|
1165
|
-
logger.
|
|
1166
|
+
logger.debug(`检测到老版本数据或无效值,使用默认阈值: 0`);
|
|
1166
1167
|
} else {
|
|
1167
1168
|
reviewParameters = existingConfig.reviewParameters;
|
|
1168
1169
|
}
|
|
@@ -1215,7 +1216,7 @@ ${config2.reminderMessage || "无"}
|
|
|
1215
1216
|
const encodedKeywords = keywordList.map((keyword) => {
|
|
1216
1217
|
return keyword.replace(/,/g, "[[COMMA]]");
|
|
1217
1218
|
});
|
|
1218
|
-
logger.
|
|
1219
|
+
logger.debug(`编码后准备存储的关键词: ${JSON.stringify(encodedKeywords)}`);
|
|
1219
1220
|
const dbData = {
|
|
1220
1221
|
keywords: encodedKeywords,
|
|
1221
1222
|
reviewMethod,
|
|
@@ -1259,24 +1260,25 @@ ${config2.reminderMessage || "无"}
|
|
|
1259
1260
|
feedbackMessage += `提醒状态: ${reminderEnabled ? "启用" : "禁用"}
|
|
1260
1261
|
`;
|
|
1261
1262
|
if (reminderMessage && reminderEnabled) {
|
|
1263
|
+
const displayReminder = reminderMessage.replace(/\\\\n/g, "").replace(/\\n/g, "\n").replace(/\x01/g, "\\n");
|
|
1262
1264
|
feedbackMessage += `提醒消息:
|
|
1263
|
-
${
|
|
1265
|
+
${displayReminder}
|
|
1264
1266
|
`;
|
|
1265
1267
|
}
|
|
1266
|
-
logger.
|
|
1267
|
-
logger.
|
|
1268
|
-
logger.
|
|
1269
|
-
logger.
|
|
1270
|
-
logger.
|
|
1271
|
-
logger.
|
|
1272
|
-
logger.
|
|
1268
|
+
logger.debug(`准备存储到数据库的关键词: ${JSON.stringify(encodedKeywords)}`);
|
|
1269
|
+
logger.debug(`=== 配置处理详情 ===`);
|
|
1270
|
+
logger.debug(`原始输入: ${keywords || "无关键词"}`);
|
|
1271
|
+
logger.debug(`审核方式: ${reviewMethod} (${["全部同意", "按数量", "按比例", "全部拒绝"][reviewMethod]})`);
|
|
1272
|
+
logger.debug(`阈值参数: ${JSON.stringify(reviewParameters)}`);
|
|
1273
|
+
logger.debug(`关键词列表: [${keywordList.map((k) => `"${k}"`).join(", ")}]`);
|
|
1274
|
+
logger.debug(`现有配置: ${existingConfig ? "存在" : "不存在"}`);
|
|
1273
1275
|
if (existingConfig) {
|
|
1274
|
-
logger.
|
|
1275
|
-
logger.
|
|
1276
|
-
logger.
|
|
1277
|
-
logger.
|
|
1276
|
+
logger.debug(`原审核方式: ${existingConfig.reviewMethod}`);
|
|
1277
|
+
logger.debug(`原阈值: ${JSON.stringify(existingConfig.reviewParameters)}`);
|
|
1278
|
+
logger.debug(`原关键词数: ${existingConfig.keywords.length}`);
|
|
1279
|
+
logger.debug(`新关键词数: ${keywordList.length}`);
|
|
1278
1280
|
}
|
|
1279
|
-
logger.
|
|
1281
|
+
logger.debug(`==================`);
|
|
1280
1282
|
logger.info(feedbackMessage.replace(/\n/g, "; "));
|
|
1281
1283
|
return feedbackMessage;
|
|
1282
1284
|
});
|
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"bugs": {
|
|
9
9
|
"url": "https://github.com/LHDyx/koishi-plugin-group-verification/issues"
|
|
10
10
|
},
|
|
11
|
-
"version": "1.0.
|
|
11
|
+
"version": "1.0.35",
|
|
12
12
|
"main": "lib/index.js",
|
|
13
13
|
"typings": "lib/index.d.ts",
|
|
14
14
|
"files": [
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"koishi": "^4.15.0"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"
|
|
48
|
-
"
|
|
47
|
+
"@types/node": "^16.0.0",
|
|
48
|
+
"typescript": "^4.9.0"
|
|
49
49
|
}
|
|
50
50
|
}
|
package/readme.md
CHANGED
|
@@ -138,11 +138,11 @@ group-verify.blacklist i <用户ID> [群号|all]
|
|
|
138
138
|
|
|
139
139
|
插件启动时会输出运行状态,并根据 `logLevel` 调整输出量。
|
|
140
140
|
- `debug`:打印所有调试细节,包括权限检查、命令解析等。
|
|
141
|
-
- `info
|
|
141
|
+
- `info`:默认值,记录关键事件(插件启动、配置修改、自动拒绝、黑名单踢人等),包括成功踢人日志。
|
|
142
142
|
- `warn`:记录可恢复的异常,例如尝试踢出用户失败、数据库操作问题。
|
|
143
143
|
- `error`:仅在遇到严重错误时输出。
|
|
144
144
|
|
|
145
|
-
添加黑名单时会尝试在对应群踢出该用户,成功记为 `info`,失败记为 `warn
|
|
145
|
+
添加黑名单时会尝试在对应群踢出该用户,成功记为 `info`,失败记为 `warn`。权限检查的详细过程则只会在 `debug` 级别输出。
|
|
146
146
|
|
|
147
147
|
### 严格群号检查
|
|
148
148
|
|