koishi-plugin-onebot-verifier 1.0.9 → 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 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
@@ -74,7 +74,17 @@ var Config = import_koishi.Schema.intersect([
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");
@@ -130,6 +140,7 @@ function apply(ctx, config = {}) {
130
140
  if (adminId) infoLines.push(`管理:${adminInfo?.name ? `${adminInfo.name}(${adminId})` : adminId}`);
131
141
  if (session.guildId) infoLines.push(`群组:${groupInfo?.name ? `${groupInfo.name}(${session.guildId})` : session.guildId}`);
132
142
  if (eventData.comment) infoLines.push(`验证信息:${eventData.comment}`);
143
+ if (status === "waiting") infoLines.push(`使用"y/n"回复本消息,以同意/拒绝该请求`);
133
144
  const content = infoLines.join("\n");
134
145
  const msgIds = await (targetType === "private" ? session.bot.sendPrivateMessage(targetId, content) : session.bot.sendMessage(targetId, content)) || [];
135
146
  return msgIds;
@@ -138,6 +149,24 @@ function apply(ctx, config = {}) {
138
149
  return [];
139
150
  }
140
151
  }, "sendNotice");
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));
165
+ }
166
+ return true;
167
+ }
168
+ return false;
169
+ }, "handleSpecialRule");
141
170
  const setupManual = /* @__PURE__ */ __name(async (session, kind) => {
142
171
  const waitMinutes = config.timeout ?? 0;
143
172
  const action = kind === "member" ? config.verifyMode : config.timeoutAction;
@@ -177,6 +206,7 @@ function apply(ctx, config = {}) {
177
206
  if (config.debugMode) logger.info(`[收到请求] 类型: ${kind} 数据: ${JSON.stringify(session.event?._data || {})}`);
178
207
  const verifyText = getComment(session.event?._data?.comment);
179
208
  if (kind === "member") {
209
+ if (await handleSpecialRule(session, kind)) return;
180
210
  const rules = config.verifyRules?.filter((r) => String(r.guildId) === String(session.guildId)) || [];
181
211
  for (const rule of rules) {
182
212
  const minL = rule.minLevel ?? 0;
@@ -255,6 +285,34 @@ function apply(ctx, config = {}) {
255
285
  logger.error(`处理失败: ${error}`);
256
286
  }
257
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");
258
316
  ctx.on("friend-request", hookEvent("friend"));
259
317
  ctx.on("guild-request", hookEvent("guild"));
260
318
  ctx.on("guild-member-request", hookEvent("member"));
@@ -286,11 +344,15 @@ function apply(ctx, config = {}) {
286
344
  const input = session.content.replace(/<(quote|at)\s+[^>]*\/>/gi, "").trim();
287
345
  const cmdMatch = input.match(/^(y|n|通过|拒绝)(?:\s+(.*))?$/i);
288
346
  if (!cmdMatch) return next();
289
- if (task.timer) clearTimeout(task.timer);
290
- task.messages.forEach((msg) => activeTasks.delete(msg));
291
347
  const isApprove = ["y", "通过"].includes(cmdMatch[1].toLowerCase());
292
348
  const extraInfo = cmdMatch[2]?.trim() || "";
293
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));
294
356
  const isSuccess = await executeAction(task.session, task.kind, isApprove, isApprove ? "" : extraInfo, isApprove && task.kind === "friend" ? extraInfo : "");
295
357
  const replyText = isSuccess ? `已${isApprove ? "通过" : "拒绝"}该请求` : `处理请求失败`;
296
358
  if (session.bot) await (targetType === "private" ? session.bot.sendPrivateMessage(targetId, replyText) : session.bot.sendMessage(targetId, replyText)).catch(() => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-onebot-verifier",
3
3
  "description": "适用于 Onebot 的审核插件,支持自动审核好友/加群/邀请请求",
4
- "version": "1.0.9",
4
+ "version": "1.0.10",
5
5
  "contributors": [
6
6
  "Yis_Rime <yis_rime@outlook.com>"
7
7
  ],