koishi-plugin-onebot-verifier 1.0.8 → 1.0.10
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 +6 -0
- package/lib/index.js +205 -146
- package/package.json +1 -1
package/lib/index.d.ts
CHANGED
|
@@ -21,6 +21,12 @@ export interface Config {
|
|
|
21
21
|
minLevel?: number;
|
|
22
22
|
action?: 'accept' | 'reject';
|
|
23
23
|
}[];
|
|
24
|
+
voteRatio?: string;
|
|
25
|
+
syncNotify?: boolean;
|
|
26
|
+
specialRules?: {
|
|
27
|
+
guildId: string;
|
|
28
|
+
mode: 'vote';
|
|
29
|
+
}[];
|
|
24
30
|
}
|
|
25
31
|
export declare const Config: Schema<Config>;
|
|
26
32
|
export declare function apply(ctx: Context, config?: Config): void;
|
package/lib/index.js
CHANGED
|
@@ -54,10 +54,10 @@ var Config = import_koishi.Schema.intersect([
|
|
|
54
54
|
import_koishi.Schema.const("accept").description("同意"),
|
|
55
55
|
import_koishi.Schema.const("reject").description("拒绝")
|
|
56
56
|
]).description("默认超时操作").default("accept"),
|
|
57
|
-
friendLevel: import_koishi.Schema.number().description("最低好友等级").default(
|
|
57
|
+
friendLevel: import_koishi.Schema.number().description("最低好友等级").default(0).min(0).max(256),
|
|
58
58
|
friendRegex: import_koishi.Schema.string().description("好友验证正则"),
|
|
59
|
-
minMembers: import_koishi.Schema.number().description("最低群成员数").default(
|
|
60
|
-
maxCapacity: import_koishi.Schema.number().description("最低受邀容量").default(
|
|
59
|
+
minMembers: import_koishi.Schema.number().description("最低群成员数").default(0).min(0).max(3e3),
|
|
60
|
+
maxCapacity: import_koishi.Schema.number().description("最低受邀容量").default(0).min(0).max(3e3)
|
|
61
61
|
}).description("好友邀群配置"),
|
|
62
62
|
import_koishi.Schema.object({
|
|
63
63
|
verifyMode: import_koishi.Schema.union([
|
|
@@ -68,37 +68,53 @@ var Config = import_koishi.Schema.intersect([
|
|
|
68
68
|
verifyRules: import_koishi.Schema.array(import_koishi.Schema.object({
|
|
69
69
|
guildId: import_koishi.Schema.string().description("群号").required(),
|
|
70
70
|
keyword: import_koishi.Schema.string().description("正则"),
|
|
71
|
-
minLevel: import_koishi.Schema.number().description("等级").default(
|
|
71
|
+
minLevel: import_koishi.Schema.number().description("等级").default(0),
|
|
72
72
|
action: import_koishi.Schema.union([
|
|
73
73
|
import_koishi.Schema.const("accept").description("同意"),
|
|
74
74
|
import_koishi.Schema.const("reject").description("拒绝")
|
|
75
75
|
]).description("操作")
|
|
76
76
|
})).description("加群验证配置").role("table")
|
|
77
|
-
}).description("加群请求配置")
|
|
77
|
+
}).description("加群请求配置"),
|
|
78
|
+
import_koishi.Schema.object({
|
|
79
|
+
syncNotify: import_koishi.Schema.boolean().description("同步通知目标").default(true),
|
|
80
|
+
specialRules: import_koishi.Schema.array(import_koishi.Schema.object({
|
|
81
|
+
guildId: import_koishi.Schema.string().description("群号").required(),
|
|
82
|
+
mode: import_koishi.Schema.union([
|
|
83
|
+
import_koishi.Schema.const("vote").description("投票")
|
|
84
|
+
]).description("模式").default("vote")
|
|
85
|
+
})).description("群组特殊配置").role("table"),
|
|
86
|
+
voteRatio: import_koishi.Schema.string().description("投票比例").default("3:2")
|
|
87
|
+
}).description("特殊验证配置")
|
|
78
88
|
]);
|
|
79
89
|
function apply(ctx, config = {}) {
|
|
80
90
|
const logger = new import_koishi.Logger("onebot-verifier");
|
|
81
91
|
const activeTasks = /* @__PURE__ */ new Map();
|
|
82
92
|
const inviterMap = /* @__PURE__ */ new Map();
|
|
93
|
+
const getComment = /* @__PURE__ */ __name((comment) => {
|
|
94
|
+
if (!comment) return "";
|
|
95
|
+
const lines = comment.split(/[\r\n]+/).map((s) => s.trim());
|
|
96
|
+
const answers = lines.filter((s) => /^(回答|答案)[::]/i.test(s)).map((s) => s.replace(/^(回答|答案)[::]\s*/i, ""));
|
|
97
|
+
return answers.length > 0 ? answers.join("\n") : comment;
|
|
98
|
+
}, "getComment");
|
|
83
99
|
const executeAction = /* @__PURE__ */ __name(async (session, kind, pass, reason = "", remark = "") => {
|
|
84
100
|
try {
|
|
85
101
|
const eventData = session.event?._data || {};
|
|
86
|
-
if (config.debugMode) logger.info(`[
|
|
102
|
+
if (config.debugMode) logger.info(`[操作] 类型:${kind} 结果:${pass ? "同意" : "拒绝"} 原因:${reason || "无"}`);
|
|
87
103
|
if (pass && kind === "guild" && session.guildId && session.userId) inviterMap.set(session.guildId, session.userId);
|
|
88
104
|
if (!pass && kind === "guild" && session.guildId && (session.event?.type === "guild-added" || eventData.notice_type === "group_increase")) {
|
|
89
|
-
if (reason) {
|
|
90
|
-
|
|
91
|
-
await session.bot.sendMessage(session.guildId, `${reason},将退出该群`);
|
|
92
|
-
} catch (error) {
|
|
93
|
-
logger.warn(`发送退群通知失败: ${error}`);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
105
|
+
if (reason) await session.bot?.sendMessage(session.guildId, `${reason},将退出该群`).catch(() => {
|
|
106
|
+
});
|
|
96
107
|
await session.onebot?.setGroupLeave(session.guildId, false);
|
|
108
|
+
if (config.debugMode) logger.info(`[操作] 退出群组: ${session.guildId}`);
|
|
97
109
|
return true;
|
|
98
110
|
}
|
|
99
|
-
|
|
100
|
-
if (
|
|
101
|
-
|
|
111
|
+
const flag = eventData.flag;
|
|
112
|
+
if (!flag || !session.onebot) return false;
|
|
113
|
+
if (kind === "friend") {
|
|
114
|
+
await session.onebot.setFriendAddRequest(flag, pass, remark);
|
|
115
|
+
} else {
|
|
116
|
+
await session.onebot.setGroupAddRequest(flag, eventData.sub_type ?? "add", pass, pass ? "" : reason);
|
|
117
|
+
}
|
|
102
118
|
return true;
|
|
103
119
|
} catch (error) {
|
|
104
120
|
logger.error(`操作失败: ${error}`);
|
|
@@ -107,143 +123,155 @@ function apply(ctx, config = {}) {
|
|
|
107
123
|
}, "executeAction");
|
|
108
124
|
const sendNotice = /* @__PURE__ */ __name(async (session, kind, status = "waiting") => {
|
|
109
125
|
const notifyConfig = config.notifyTarget || "";
|
|
110
|
-
if (!notifyConfig) return [];
|
|
111
126
|
const [targetType, targetId] = notifyConfig.split(":");
|
|
112
|
-
if (!targetId ||
|
|
127
|
+
if (!targetId || !session.bot) return [];
|
|
113
128
|
try {
|
|
114
129
|
const eventData = session.event?._data || {};
|
|
115
|
-
const userInfo = session.userId ? await session.bot.getUser?.(session.userId)
|
|
116
|
-
const groupInfo = kind !== "friend" && session.guildId ? await session.bot.getGuild?.(session.guildId)
|
|
117
|
-
const adminId = eventData.operator_id || session.event
|
|
118
|
-
const adminInfo = adminId &&
|
|
130
|
+
const userInfo = session.userId ? await session.bot.getUser?.(session.userId).catch(() => null) : null;
|
|
131
|
+
const groupInfo = kind !== "friend" && session.guildId ? await session.bot.getGuild?.(session.guildId).catch(() => null) : null;
|
|
132
|
+
const adminId = String(eventData.operator_id || session.event?.operator?.id || "");
|
|
133
|
+
const adminInfo = adminId && adminId !== session.userId ? await session.bot.getUser?.(adminId).catch(() => null) : null;
|
|
134
|
+
const typeMap = { friend: "好友申请", member: "加群请求", guild: "群组邀请", removed: eventData.sub_type === "kick_me" ? "移出群组" : "退出群组" };
|
|
135
|
+
const statusMap = { auto_pass: " [自动通过]", auto_reject: " [自动拒绝]", waiting: " [等待处理]" };
|
|
119
136
|
const infoLines = [];
|
|
120
137
|
if (userInfo?.avatar) infoLines.push(`<image url="${userInfo.avatar}"/>`);
|
|
121
|
-
|
|
122
|
-
if (kind
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
else if (kind === "removed") typeName = eventData.sub_type === "kick_me" ? "机器人被踢" : "机器人退群";
|
|
126
|
-
let statusText = "";
|
|
127
|
-
if (kind === "removed") {
|
|
128
|
-
if (eventData.sub_type === "kick_me" && config.kickBan) statusText = " [自动清理]";
|
|
129
|
-
} else {
|
|
130
|
-
statusText = status === "auto_pass" ? " [自动通过]" : status === "auto_reject" ? " [自动拒绝]" : " [等待处理]";
|
|
131
|
-
}
|
|
132
|
-
infoLines.push(`类型:${typeName}${statusText}`);
|
|
133
|
-
if (kind !== "guild" && kind !== "removed" || session.userId !== session.selfId) {
|
|
134
|
-
infoLines.push(`用户:${userInfo?.name || session.userId}${session.userId ? `(${session.userId})` : ""}`);
|
|
135
|
-
}
|
|
136
|
-
if (adminInfo) infoLines.push(`管理:${adminInfo.name ? `${adminInfo.name}(${adminId})` : adminId}`);
|
|
137
|
-
if (groupInfo) infoLines.push(`群组:${groupInfo.name ? `${groupInfo.name}(${session.guildId})` : session.guildId}`);
|
|
138
|
+
infoLines.push(`类型:${typeMap[kind] || "未知"}${kind === "removed" ? eventData.sub_type === "kick_me" && config.kickBan ? " [自动清理]" : "" : statusMap[status]}`);
|
|
139
|
+
if (kind !== "guild" && kind !== "removed" || session.userId && session.userId !== session.selfId) infoLines.push(`用户:${userInfo?.name || session.userId}${session.userId ? `(${session.userId})` : ""}`);
|
|
140
|
+
if (adminId) infoLines.push(`管理:${adminInfo?.name ? `${adminInfo.name}(${adminId})` : adminId}`);
|
|
141
|
+
if (session.guildId) infoLines.push(`群组:${groupInfo?.name ? `${groupInfo.name}(${session.guildId})` : session.guildId}`);
|
|
138
142
|
if (eventData.comment) infoLines.push(`验证信息:${eventData.comment}`);
|
|
143
|
+
if (status === "waiting") infoLines.push(`使用"y/n"回复本消息,以同意/拒绝该请求`);
|
|
139
144
|
const content = infoLines.join("\n");
|
|
140
|
-
|
|
145
|
+
const msgIds = await (targetType === "private" ? session.bot.sendPrivateMessage(targetId, content) : session.bot.sendMessage(targetId, content)) || [];
|
|
146
|
+
return msgIds;
|
|
141
147
|
} catch (error) {
|
|
142
148
|
logger.error(`通知失败: ${error}`);
|
|
143
149
|
return [];
|
|
144
150
|
}
|
|
145
151
|
}, "sendNotice");
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
if (
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
const isPassed = (stats.qqLevel ?? 0) >= limitLevel;
|
|
160
|
-
if (config.debugMode) logger.info(`[规则判定] 等级检查: ${stats.qqLevel} > ${limitLevel} = ${isPassed}`);
|
|
161
|
-
if (!isPassed) return `QQ 等级低于 ${limitLevel} 级`;
|
|
162
|
-
return true;
|
|
163
|
-
}
|
|
164
|
-
} catch {
|
|
165
|
-
return false;
|
|
152
|
+
const handleSpecialRule = /* @__PURE__ */ __name(async (session, kind) => {
|
|
153
|
+
if (kind !== "member" || !config.specialRules || config.specialRules.length === 0) return false;
|
|
154
|
+
const rule = config.specialRules.find((r) => String(r.guildId) === String(session.guildId));
|
|
155
|
+
if (!rule) return false;
|
|
156
|
+
if (rule.mode === "vote") {
|
|
157
|
+
const [yesStr, noStr] = config.voteRatio.split(":");
|
|
158
|
+
const targetYes = parseInt(yesStr) || 0;
|
|
159
|
+
const targetNo = parseInt(noStr) || 0;
|
|
160
|
+
let msgIds = [];
|
|
161
|
+
if (config.syncNotify !== false) msgIds = await sendNotice(session, kind, "waiting");
|
|
162
|
+
if (msgIds.length > 0) {
|
|
163
|
+
const task = { session, kind, messages: msgIds, specialMode: "vote", voteTarget: { yes: targetYes, no: targetNo }, votes: { yes: /* @__PURE__ */ new Set(), no: /* @__PURE__ */ new Set() } };
|
|
164
|
+
msgIds.forEach((id) => activeTasks.set(id, task));
|
|
166
165
|
}
|
|
167
|
-
return
|
|
168
|
-
}
|
|
169
|
-
if (kind === "guild") {
|
|
170
|
-
try {
|
|
171
|
-
const userData = session.userId ? await ctx.database.getUser(session.platform, session.userId) : null;
|
|
172
|
-
if (userData && userData.authority > 1) {
|
|
173
|
-
if (config.debugMode) logger.info(`[规则匹配] 白名单: ${userData.authority}`);
|
|
174
|
-
return true;
|
|
175
|
-
}
|
|
176
|
-
} catch {
|
|
177
|
-
}
|
|
178
|
-
if (session.onebot && session.guildId && ((config.minMembers ?? -1) >= 0 || (config.maxCapacity ?? -1) >= 0)) {
|
|
179
|
-
try {
|
|
180
|
-
const stats = await session.onebot.getGroupInfo(session.guildId, true);
|
|
181
|
-
if ((config.minMembers ?? -1) >= 0 && stats.member_count < (config.minMembers ?? 0)) {
|
|
182
|
-
if (config.debugMode) logger.info(`[规则判定] 成员检查: ${stats.member_count} < ${config.minMembers}`);
|
|
183
|
-
return `群成员不足 ${config.minMembers} 人`;
|
|
184
|
-
}
|
|
185
|
-
if ((config.maxCapacity ?? -1) >= 0 && stats.max_member_count < (config.maxCapacity ?? 0)) {
|
|
186
|
-
if (config.debugMode) logger.info(`[规则判定] 容量检查: ${stats.max_member_count} < ${config.maxCapacity}`);
|
|
187
|
-
return `群容量不足 ${config.maxCapacity} 人`;
|
|
188
|
-
}
|
|
189
|
-
return true;
|
|
190
|
-
} catch {
|
|
191
|
-
return false;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
return false;
|
|
166
|
+
return true;
|
|
195
167
|
}
|
|
196
168
|
return false;
|
|
197
|
-
}, "
|
|
169
|
+
}, "handleSpecialRule");
|
|
198
170
|
const setupManual = /* @__PURE__ */ __name(async (session, kind) => {
|
|
199
|
-
const msgIds = await sendNotice(session, kind, "waiting");
|
|
200
|
-
if (!msgIds?.length) return;
|
|
201
|
-
const task = { session, kind, messages: msgIds };
|
|
202
|
-
msgIds.forEach((id) => activeTasks.set(id, task));
|
|
203
171
|
const waitMinutes = config.timeout ?? 0;
|
|
172
|
+
const action = kind === "member" ? config.verifyMode : config.timeoutAction;
|
|
204
173
|
if (waitMinutes > 0) {
|
|
174
|
+
const msgIds = await sendNotice(session, kind, "waiting");
|
|
175
|
+
if (!msgIds?.length) return;
|
|
176
|
+
const task = { session, kind, messages: msgIds };
|
|
177
|
+
msgIds.forEach((id) => activeTasks.set(id, task));
|
|
205
178
|
task.timer = setTimeout(async () => {
|
|
206
179
|
if (!activeTasks.has(msgIds[0])) return;
|
|
207
180
|
msgIds.forEach((id) => activeTasks.delete(id));
|
|
208
|
-
const
|
|
209
|
-
if (
|
|
210
|
-
const isPass =
|
|
211
|
-
await executeAction(session, kind, isPass, isPass ? "" : "
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
if (targetId) {
|
|
181
|
+
const finalAction = kind === "member" ? config.verifyMode ?? "manual" : config.timeoutAction ?? "accept";
|
|
182
|
+
if (finalAction === "manual") return;
|
|
183
|
+
const isPass = finalAction === "accept";
|
|
184
|
+
await executeAction(session, kind, isPass, isPass ? "" : "等待超时,自动拒绝");
|
|
185
|
+
const [targetType, targetId] = (config.notifyTarget || "").split(":");
|
|
186
|
+
if (targetId && session.bot) {
|
|
215
187
|
const statusText = `已自动${isPass ? "通过" : "拒绝"}该请求`;
|
|
216
|
-
await (targetType === "private" ? session.bot.sendPrivateMessage(targetId, statusText) : session.bot.sendMessage(targetId, statusText))
|
|
188
|
+
await (targetType === "private" ? session.bot.sendPrivateMessage(targetId, statusText) : session.bot.sendMessage(targetId, statusText)).catch(() => {
|
|
189
|
+
});
|
|
217
190
|
}
|
|
191
|
+
if (config.debugMode) logger.info(`[操作] 等待超时,默认${isPass ? "通过" : "拒绝"}`);
|
|
218
192
|
}, waitMinutes * 6e4);
|
|
193
|
+
} else {
|
|
194
|
+
if (action === "manual" || !action) return await sendNotice(session, kind, "waiting");
|
|
195
|
+
const isPass = action === "accept";
|
|
196
|
+
await executeAction(session, kind, isPass, "等待超时,自动处理");
|
|
197
|
+
await sendNotice(session, kind, isPass ? "auto_pass" : "auto_reject");
|
|
198
|
+
if (config.debugMode) logger.info(`[操作] 无需等待,默认${isPass ? "通过" : "拒绝"}`);
|
|
219
199
|
}
|
|
220
200
|
}, "setupManual");
|
|
221
|
-
const
|
|
201
|
+
const hookEvent = /* @__PURE__ */ __name((kind) => async (session) => {
|
|
202
|
+
const eventData = session.event?._data || {};
|
|
203
|
+
if (eventData.user_id) session.userId = String(eventData.user_id);
|
|
204
|
+
if (eventData.group_id) session.guildId = String(eventData.group_id);
|
|
222
205
|
try {
|
|
223
|
-
if (config.debugMode) logger.info(`[收到请求] 类型: ${kind}
|
|
206
|
+
if (config.debugMode) logger.info(`[收到请求] 类型: ${kind} 数据: ${JSON.stringify(session.event?._data || {})}`);
|
|
207
|
+
const verifyText = getComment(session.event?._data?.comment);
|
|
224
208
|
if (kind === "member") {
|
|
209
|
+
if (await handleSpecialRule(session, kind)) return;
|
|
225
210
|
const rules = config.verifyRules?.filter((r) => String(r.guildId) === String(session.guildId)) || [];
|
|
226
|
-
|
|
227
|
-
const
|
|
228
|
-
const
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
211
|
+
for (const rule of rules) {
|
|
212
|
+
const minL = rule.minLevel ?? 0;
|
|
213
|
+
const stats = minL > 0 && session.onebot && session.userId ? await session.onebot.getStrangerInfo(session.userId, true).catch(() => ({})) : null;
|
|
214
|
+
const keywordMatch = !rule.keyword || new RegExp(rule.keyword, "i").test(verifyText);
|
|
215
|
+
const levelMatch = !stats || (stats.qqLevel ?? 0) >= minL;
|
|
216
|
+
if (config.debugMode) {
|
|
217
|
+
if (rule.keyword) logger.info(`[加群验证] 内容 "${verifyText}" ${keywordMatch ? "匹配" : "不匹配"}正则 "${rule.keyword}"`);
|
|
218
|
+
if (stats) logger.info(`[加群验证] 用户 ${session.userId} 等级 ${stats.qqLevel ?? 0}${levelMatch ? ">" : "<"}${minL}`);
|
|
219
|
+
}
|
|
220
|
+
if (keywordMatch && levelMatch && rule.action) {
|
|
221
|
+
const isApprove = rule.action === "accept";
|
|
222
|
+
await executeAction(session, kind, isApprove, isApprove ? "" : "命中规则,自动拒绝");
|
|
223
|
+
await sendNotice(session, kind, isApprove ? "auto_pass" : "auto_reject");
|
|
224
|
+
return;
|
|
242
225
|
}
|
|
243
226
|
}
|
|
227
|
+
if (config.verifyMode && config.verifyMode !== "manual") {
|
|
228
|
+
const isApprove = config.verifyMode === "accept";
|
|
229
|
+
await executeAction(session, kind, isApprove, "等待超时,自动处理");
|
|
230
|
+
await sendNotice(session, kind, isApprove ? "auto_pass" : "auto_reject");
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
244
233
|
return await setupManual(session, kind);
|
|
245
234
|
}
|
|
246
|
-
|
|
235
|
+
let verdict = false;
|
|
236
|
+
if (kind === "friend") {
|
|
237
|
+
if (config.friendRegex) {
|
|
238
|
+
const isRegexMatched = new RegExp(config.friendRegex, "i").test(verifyText);
|
|
239
|
+
if (config.debugMode) logger.info(`[好友验证] 内容 "${verifyText}" ${isRegexMatched ? "匹配" : "不匹配"}正则 "${config.friendRegex}" `);
|
|
240
|
+
if (isRegexMatched) verdict = true;
|
|
241
|
+
}
|
|
242
|
+
if (verdict !== true) {
|
|
243
|
+
const fLevel = config.friendLevel ?? 0;
|
|
244
|
+
if (fLevel > 0 && session.onebot && session.userId) {
|
|
245
|
+
const stats = await session.onebot.getStrangerInfo(session.userId, true).catch(() => ({}));
|
|
246
|
+
const isLevelMatched = (stats.qqLevel ?? 0) >= fLevel;
|
|
247
|
+
if (config.debugMode) logger.info(`[好友验证] 用户 ${session.userId} 等级 ${stats.qqLevel ?? 0}${isLevelMatched ? ">" : "<"}${fLevel}`);
|
|
248
|
+
if (isLevelMatched) verdict = true;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
} else if (kind === "guild") {
|
|
252
|
+
if (ctx.database && session.userId) {
|
|
253
|
+
const userData = await ctx.database.getUser(session.platform, session.userId, ["authority"]).catch(() => null);
|
|
254
|
+
if (userData && userData.authority > 3) {
|
|
255
|
+
if (config.debugMode) logger.info(`[群组邀请] 用户 ${session.userId} 权限 ${userData.authority}>3`);
|
|
256
|
+
verdict = true;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (verdict !== true && session.onebot && session.guildId) {
|
|
260
|
+
const stats = await session.onebot.getGroupInfo(session.guildId, true).catch(() => ({}));
|
|
261
|
+
const minM = config.minMembers ?? 0;
|
|
262
|
+
const maxC = config.maxCapacity ?? 0;
|
|
263
|
+
if (minM > 0 && (stats.member_count ?? 0) < minM) {
|
|
264
|
+
verdict = `群成员不足 ${minM} 人`;
|
|
265
|
+
if (config.debugMode) logger.info(`[群组邀请] 群组 ${session.guildId} 成员数 ${stats.member_count ?? 0}<${minM}`);
|
|
266
|
+
} else if (maxC > 0 && (stats.max_member_count ?? 0) < maxC) {
|
|
267
|
+
verdict = `群容量不足 ${maxC} 人`;
|
|
268
|
+
if (config.debugMode) logger.info(`[群组邀请] 群组 ${session.guildId} 受邀容量 ${stats.max_member_count ?? 0}<${maxC}`);
|
|
269
|
+
} else {
|
|
270
|
+
verdict = minM > 0 || maxC > 0;
|
|
271
|
+
if (config.debugMode && verdict) logger.info(`[群组邀请] 群组 ${session.guildId} 成员数 ${stats.member_count ?? 0}>${minM},受邀容量 ${stats.max_member_count ?? 0}>${maxC}`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
247
275
|
if (verdict === true) {
|
|
248
276
|
await executeAction(session, kind, true);
|
|
249
277
|
await sendNotice(session, kind, "auto_pass");
|
|
@@ -256,48 +284,79 @@ function apply(ctx, config = {}) {
|
|
|
256
284
|
} catch (error) {
|
|
257
285
|
logger.error(`处理失败: ${error}`);
|
|
258
286
|
}
|
|
259
|
-
}, "handleEvent");
|
|
260
|
-
const hookEvent = /* @__PURE__ */ __name((kind) => async (session) => {
|
|
261
|
-
const eventData = session.event?._data || {};
|
|
262
|
-
session.userId = eventData.user_id;
|
|
263
|
-
if (kind !== "friend") session.guildId = eventData.group_id;
|
|
264
|
-
await handleEvent(session, kind);
|
|
265
287
|
}, "hookEvent");
|
|
288
|
+
const handleSpecialVote = /* @__PURE__ */ __name(async (session, task, isApprove, extraInfo, targetType, targetId) => {
|
|
289
|
+
if (!task.voteTarget || !task.votes) return;
|
|
290
|
+
const voterId = session.userId;
|
|
291
|
+
if (!voterId) return;
|
|
292
|
+
task.votes.yes.delete(voterId);
|
|
293
|
+
task.votes.no.delete(voterId);
|
|
294
|
+
if (isApprove) {
|
|
295
|
+
task.votes.yes.add(voterId);
|
|
296
|
+
} else {
|
|
297
|
+
task.votes.no.add(voterId);
|
|
298
|
+
}
|
|
299
|
+
if (config.debugMode) logger.info(`[投票] 赞成: ${task.votes.yes.size}/${task.voteTarget.yes} | 反对: ${task.votes.no.size}/${task.voteTarget.no}`);
|
|
300
|
+
let thresholdMet = false;
|
|
301
|
+
let finalVerdict = false;
|
|
302
|
+
if (task.voteTarget.yes > 0 && task.votes.yes.size >= task.voteTarget.yes) {
|
|
303
|
+
thresholdMet = true;
|
|
304
|
+
finalVerdict = true;
|
|
305
|
+
} else if (task.voteTarget.no > 0 && task.votes.no.size >= task.voteTarget.no) {
|
|
306
|
+
thresholdMet = true;
|
|
307
|
+
finalVerdict = false;
|
|
308
|
+
}
|
|
309
|
+
if (!thresholdMet) return;
|
|
310
|
+
task.messages.forEach((msg) => activeTasks.delete(msg));
|
|
311
|
+
const isSuccess = await executeAction(task.session, task.kind, finalVerdict, finalVerdict ? "" : extraInfo);
|
|
312
|
+
const replyText = isSuccess ? `已${finalVerdict ? "通过" : "拒绝"}该投票` : `处理投票失败`;
|
|
313
|
+
if (session.bot) await (targetType === "private" ? session.bot.sendPrivateMessage(targetId, replyText) : session.bot.sendMessage(targetId, replyText)).catch(() => {
|
|
314
|
+
});
|
|
315
|
+
}, "handleSpecialVote");
|
|
266
316
|
ctx.on("friend-request", hookEvent("friend"));
|
|
267
317
|
ctx.on("guild-request", hookEvent("guild"));
|
|
268
318
|
ctx.on("guild-member-request", hookEvent("member"));
|
|
269
319
|
ctx.on("guild-added", hookEvent("guild"));
|
|
270
320
|
ctx.on("guild-removed", async (session) => {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
321
|
+
if (session.event?._data?.sub_type === "kick_me") {
|
|
322
|
+
const gid = session.guildId;
|
|
323
|
+
if (gid) {
|
|
324
|
+
const inviterId = inviterMap.get(gid);
|
|
325
|
+
if (inviterId) {
|
|
326
|
+
await session.onebot?.deleteFriend(inviterId).catch(() => {
|
|
327
|
+
});
|
|
328
|
+
inviterMap.delete(gid);
|
|
329
|
+
if (config.debugMode) logger.info(`[操作] 删除好友: ${inviterId}`);
|
|
330
|
+
}
|
|
331
|
+
await session.execute(`analyse.clear -g ${gid}`).catch(() => {
|
|
332
|
+
});
|
|
277
333
|
}
|
|
278
|
-
await session.execute(`analyse.clear -g ${session.guildId}`).catch(() => {
|
|
279
|
-
});
|
|
280
334
|
}
|
|
281
335
|
await sendNotice(session, "removed");
|
|
282
336
|
});
|
|
283
337
|
ctx.middleware(async (session, next) => {
|
|
284
338
|
if (typeof session.content !== "string" || !session.quote?.id) return next();
|
|
285
|
-
const
|
|
286
|
-
if (!
|
|
287
|
-
const
|
|
288
|
-
const
|
|
289
|
-
if (
|
|
339
|
+
const task = activeTasks.get(session.quote.id);
|
|
340
|
+
if (!task) return next();
|
|
341
|
+
const [targetType, targetId] = (config.notifyTarget || "").split(":");
|
|
342
|
+
const isMatched = targetType === "private" ? session.userId === targetId : session.guildId === targetId;
|
|
343
|
+
if (!isMatched) return next();
|
|
290
344
|
const input = session.content.replace(/<(quote|at)\s+[^>]*\/>/gi, "").trim();
|
|
291
|
-
const cmdMatch = input.match(/^(y|n|通过|拒绝)(?:\s+(.*))?$/);
|
|
345
|
+
const cmdMatch = input.match(/^(y|n|通过|拒绝)(?:\s+(.*))?$/i);
|
|
292
346
|
if (!cmdMatch) return next();
|
|
293
|
-
|
|
294
|
-
activeTask.messages.forEach((msg) => activeTasks.delete(msg));
|
|
295
|
-
const isApprove = cmdMatch[1] === "y" || cmdMatch[1] === "通过";
|
|
347
|
+
const isApprove = ["y", "通过"].includes(cmdMatch[1].toLowerCase());
|
|
296
348
|
const extraInfo = cmdMatch[2]?.trim() || "";
|
|
297
|
-
if (config.debugMode) logger.info(`[
|
|
298
|
-
|
|
349
|
+
if (config.debugMode) logger.info(`[操作] 收到指令: ${isApprove ? "同意" : "拒绝"}`);
|
|
350
|
+
if (task.specialMode === "vote") {
|
|
351
|
+
await handleSpecialVote(session, task, isApprove, extraInfo, targetType, targetId);
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
if (task.timer) clearTimeout(task.timer);
|
|
355
|
+
task.messages.forEach((msg) => activeTasks.delete(msg));
|
|
356
|
+
const isSuccess = await executeAction(task.session, task.kind, isApprove, isApprove ? "" : extraInfo, isApprove && task.kind === "friend" ? extraInfo : "");
|
|
299
357
|
const replyText = isSuccess ? `已${isApprove ? "通过" : "拒绝"}该请求` : `处理请求失败`;
|
|
300
|
-
await (targetType === "private" ? session.bot.sendPrivateMessage(targetId, replyText) : session.bot.sendMessage(targetId, replyText))
|
|
358
|
+
if (session.bot) await (targetType === "private" ? session.bot.sendPrivateMessage(targetId, replyText) : session.bot.sendMessage(targetId, replyText)).catch(() => {
|
|
359
|
+
});
|
|
301
360
|
});
|
|
302
361
|
}
|
|
303
362
|
__name(apply, "apply");
|