koishi-plugin-group-verification 1.0.2 → 1.0.4

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
@@ -16,6 +16,8 @@ export interface GroupVerificationConfig {
16
16
  threshold?: number;
17
17
  };
18
18
  reminderMessage: string;
19
+ createdBy: string;
20
+ updatedBy: string;
19
21
  createdAt: Date;
20
22
  updatedAt: Date;
21
23
  }
package/lib/index.js CHANGED
@@ -36,6 +36,8 @@ function apply(ctx, config) {
36
36
  reviewMethod: "integer",
37
37
  reviewParameters: "json",
38
38
  reminderMessage: "string",
39
+ createdBy: "string",
40
+ updatedBy: "string",
39
41
  createdAt: "date",
40
42
  updatedAt: "date"
41
43
  }, {
@@ -75,7 +77,7 @@ function apply(ctx, config) {
75
77
  return;
76
78
  }
77
79
  const config2 = groupConfig[0];
78
- const isValid = await verifyApplication(config2, message);
80
+ const { isValid, matchedCount, requiredThreshold } = await verifyApplication(config2, message, session);
79
81
  if (isValid) {
80
82
  await updateStats(guildId, "autoApproved");
81
83
  } else {
@@ -87,6 +89,13 @@ function apply(ctx, config) {
87
89
  const userId = session.userId;
88
90
  const username = session.username || "未知用户";
89
91
  const message = session.content || "";
92
+ let groupName = "未知群组";
93
+ try {
94
+ const guild = await session.bot.getGuild(guildId);
95
+ groupName = guild.name || groupName;
96
+ } catch (error) {
97
+ }
98
+ const { matchedCount, requiredThreshold } = await verifyApplication(config2, message, session);
90
99
  await ctx2.database.create("group_verification_pending", {
91
100
  groupId: guildId,
92
101
  userId,
@@ -94,30 +103,41 @@ function apply(ctx, config) {
94
103
  requestMessage: message,
95
104
  applyTime: /* @__PURE__ */ new Date()
96
105
  });
97
- const reminderMsg = config2.reminderMessage || `收到新的加群申请:${username}(${userId})
98
- 申请理由:${message}
99
- 请管理员使用 #同意 或 #拒绝 来处理此申请`;
106
+ let reminderMsg = config2.reminderMessage;
107
+ 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);
100
108
  await ctx2.broadcast([guildId], reminderMsg);
101
109
  }
102
110
  __name(handleFailedVerification, "handleFailedVerification");
103
- async function verifyApplication(config2, message) {
111
+ async function verifyApplication(config2, message, session) {
104
112
  const matchedCount = config2.keywords.filter(
105
113
  (keyword) => message.toLowerCase().includes(keyword.toLowerCase())
106
114
  ).length;
115
+ let isValid = false;
116
+ let requiredThreshold = "";
107
117
  switch (config2.reviewMethod) {
108
118
  case 0:
109
- return true;
119
+ isValid = true;
120
+ requiredThreshold = "null";
121
+ break;
110
122
  case 1:
111
- return matchedCount >= (config2.reviewParameters.threshold || 1);
123
+ isValid = matchedCount >= (config2.reviewParameters.threshold || 1);
124
+ requiredThreshold = `${config2.reviewParameters.threshold || 1}`;
125
+ break;
112
126
  case 2:
113
127
  const ratio = matchedCount / config2.keywords.length;
114
128
  const requiredRatio = (config2.reviewParameters.threshold || 100) / 100;
115
- return ratio >= requiredRatio;
129
+ isValid = ratio >= requiredRatio;
130
+ requiredThreshold = `${config2.reviewParameters.threshold || 100}%`;
131
+ break;
116
132
  case 3:
117
- return false;
133
+ isValid = false;
134
+ requiredThreshold = "null";
135
+ break;
118
136
  default:
119
- return false;
137
+ isValid = false;
138
+ requiredThreshold = "null";
120
139
  }
140
+ return { isValid, matchedCount, requiredThreshold };
121
141
  }
122
142
  __name(verifyApplication, "verifyApplication");
123
143
  async function updateStats(groupId, statType) {
@@ -157,29 +177,53 @@ function apply(ctx, config) {
157
177
  __name(updateStats, "updateStats");
158
178
  async function checkPermission(session, targetGroupId) {
159
179
  const groupId = targetGroupId || session.guildId;
160
- if (groupId) {
161
- try {
162
- const member = await session.bot.getGuildMember(groupId, session.userId);
163
- if (member && (member.roles?.includes("admin") || member.permissions?.includes("ADMINISTRATOR"))) {
164
- return true;
165
- }
166
- } catch (error) {
167
- }
180
+ if (!groupId) {
181
+ return [false, "请在群聊中使用此命令或使用 -i 参数指定群号"];
168
182
  }
183
+ console.log(`[权限检查] 用户ID: ${session.userId}, 群号: ${groupId}`);
184
+ console.log(`[权限检查] Koishi权限等级: ${session.author?.authority || "未获取到"}`);
169
185
  if (session.author?.authority && session.author.authority >= 3) {
170
- return true;
186
+ console.log(`[权限检查] 通过koishi权限检查: ${session.author.authority}`);
187
+ return [true];
188
+ }
189
+ try {
190
+ const member = await session.bot.getGuildMember(groupId, session.userId);
191
+ console.log(`[权限检查] 获取到成员信息:`, {
192
+ roles: member?.roles,
193
+ permissions: member?.permissions
194
+ });
195
+ if (member) {
196
+ if (member.permissions?.includes("OWNER")) {
197
+ console.log(`[权限检查] 用户是群主`);
198
+ return [true];
199
+ }
200
+ if (member.roles?.includes("admin") || member.permissions?.includes("ADMINISTRATOR")) {
201
+ console.log(`[权限检查] 用户是管理员`);
202
+ return [true];
203
+ }
204
+ }
205
+ } catch (error) {
206
+ console.log(`[权限检查] 获取群成员信息失败:`, error);
207
+ return [false, `无法获取群 ${groupId} 的成员信息,请确认机器人已在该群中`];
171
208
  }
172
- return false;
209
+ console.log(`[权限检查] 权限不足`);
210
+ return [false, "权限不足:需要群主/管理员权限或koishi三级以上权限"];
173
211
  }
174
212
  __name(checkPermission, "checkPermission");
175
- const groupVerify = ctx.command("group-verify", "群组验证管理命令");
176
- groupVerify.subcommand(".config [keywords:text]", "配置群组验证规则").alias("cfg", "配置", "conf", "设置").option("groupId", "-i <groupId> 指定群号").option("method", "-m <method> 审核方式 (0-3)").option("threshold", "-t <threshold> 阈值参数").option("query", "-? 查询当前配置").option("remove", "-r 删除配置").action(async ({ session, options }, keywords) => {
213
+ const groupVerify = ctx.command("group-verify", "群组验证管理命令").alias("gv", "gverify");
214
+ groupVerify.subcommand(".config [keywords:text]", "配置群组验证规则").alias("cfg", "配置", "conf", "设置").option("groupId", "-i <groupId> 指定群号").option("method", "-m <method> 审核方式 (0-3)").option("threshold", "-t <threshold> 阈值参数").option("message", "-msg <message> 自定义提醒消息").option("query", "-? 查询当前配置").option("remove", "-r 删除配置").action(async ({ session, options }, keywords) => {
177
215
  const targetGroupId = options.groupId || session.guildId;
178
- if (!await checkPermission(session, targetGroupId)) {
179
- return "权限不足";
216
+ const [hasPermission, errorMsg] = await checkPermission(session, targetGroupId);
217
+ if (!hasPermission) {
218
+ return errorMsg || "权限不足";
180
219
  }
181
- if (!targetGroupId) {
182
- return "请在群聊中使用此命令或使用 -i 参数指定群号";
220
+ let groupName = "未知群组";
221
+ if (targetGroupId) {
222
+ try {
223
+ const guild = await session.bot.getGuild(targetGroupId);
224
+ groupName = guild.name || groupName;
225
+ } catch (error) {
226
+ }
183
227
  }
184
228
  if (options.remove) {
185
229
  const existingConfig2 = await ctx.database.get("group_verification_config", { groupId: targetGroupId });
@@ -195,34 +239,41 @@ function apply(ctx, config) {
195
239
  if (existingConfig2.length > 0) {
196
240
  const config2 = existingConfig2[0];
197
241
  let methodDesc = "";
242
+ let thresholdInfo = "";
198
243
  switch (config2.reviewMethod) {
199
244
  case 0:
200
245
  methodDesc = "全部同意";
246
+ thresholdInfo = "null";
201
247
  break;
202
248
  case 1:
203
- methodDesc = `按数量同意 (${config2.reviewParameters.threshold || 1})`;
249
+ methodDesc = `按数量同意`;
250
+ thresholdInfo = `${config2.reviewParameters.threshold || 1}`;
204
251
  break;
205
252
  case 2:
206
- methodDesc = `按比例同意 (${config2.reviewParameters.threshold || 100}%)`;
253
+ methodDesc = `按比例同意`;
254
+ thresholdInfo = `${config2.reviewParameters.threshold || 100}%`;
207
255
  break;
208
256
  case 3:
209
257
  methodDesc = "全部拒绝";
258
+ thresholdInfo = "null";
210
259
  break;
211
260
  }
261
+ const createTime = new Date(config2.createdAt).toLocaleString("zh-CN", { timeZone: "Asia/Shanghai" });
262
+ const updateTime = new Date(config2.updatedAt).toLocaleString("zh-CN", { timeZone: "Asia/Shanghai" });
212
263
  return `群 ${targetGroupId} 配置:
213
264
  关键词: ${config2.keywords.join(", ")}
214
- 审核方式: ${methodDesc}`;
265
+ 审核方式: ${methodDesc}
266
+ 阈值: ${thresholdInfo}
267
+ 提醒消息: ${config2.reminderMessage}
268
+ 创建时间: ${createTime}
269
+ 更新时间: ${updateTime}
270
+ 创建者: ${config2.createdBy}
271
+ 更新者: ${config2.updatedBy}`;
215
272
  } else {
216
273
  return `群 ${targetGroupId} 无验证配置`;
217
274
  }
218
275
  }
219
- if (!keywords) {
220
- return "请提供关键词参数,或使用 -? 查询配置,-r 删除配置";
221
- }
222
- const keywordList = keywords.split(",").map((k) => k.trim()).filter((k) => k);
223
- if (keywordList.length === 0) {
224
- return "请提供有效的关键词";
225
- }
276
+ const keywordList = keywords ? keywords.split(",").map((k) => k.trim()).filter((k) => k) : [];
226
277
  let reviewMethod = 0;
227
278
  let reviewParameters = {};
228
279
  if (options.method !== void 0) {
@@ -249,25 +300,30 @@ function apply(ctx, config) {
249
300
  }
250
301
  }
251
302
  }
303
+ let reminderMessage = options.message || `用户 {user}({id}) 申请加入群 {gname}({group})
304
+ 申请理由:{question}
305
+ 答对情况:{answer}
306
+ 阈值要求:{threshold}
307
+ 请管理员使用 #同意 或 #拒绝 来处理此申请`;
308
+ reminderMessage = reminderMessage.replace(/\\n/g, "\n");
252
309
  const existingConfig = await ctx.database.get("group_verification_config", { groupId: targetGroupId });
310
+ const configData = {
311
+ keywords: keywordList,
312
+ reviewMethod,
313
+ reviewParameters,
314
+ reminderMessage,
315
+ updatedBy: session.username || session.userId,
316
+ updatedAt: /* @__PURE__ */ new Date()
317
+ };
253
318
  if (existingConfig.length > 0) {
254
- await ctx.database.set("group_verification_config", { id: existingConfig[0].id }, {
255
- keywords: keywordList,
256
- reviewMethod,
257
- reviewParameters,
258
- reminderMessage: `New join request received. Please use #approve or #reject to handle this request`,
259
- updatedAt: /* @__PURE__ */ new Date()
260
- });
319
+ await ctx.database.set("group_verification_config", { id: existingConfig[0].id }, configData);
261
320
  return `已更新群 ${targetGroupId} 的验证配置`;
262
321
  } else {
263
322
  await ctx.database.create("group_verification_config", {
323
+ ...configData,
264
324
  groupId: targetGroupId,
265
- keywords: keywordList,
266
- reviewMethod,
267
- reviewParameters,
268
- reminderMessage: `New join request received. Please use #approve or #reject to handle this request`,
269
- createdAt: /* @__PURE__ */ new Date(),
270
- updatedAt: /* @__PURE__ */ new Date()
325
+ createdBy: session.username || session.userId,
326
+ createdAt: /* @__PURE__ */ new Date()
271
327
  });
272
328
  return `已为群 ${targetGroupId} 创建验证配置`;
273
329
  }
@@ -357,19 +413,42 @@ function apply(ctx, config) {
357
413
  });
358
414
  groupVerify.subcommand(".help", "显示帮助信息").alias("帮助", "hlp", "帮助信息").action(() => {
359
415
  return `群组验证命令帮助:
360
- .config [关键词] [选项] - 配置验证规则
361
- 选项:-i 群号 -m 方式(0-3) -t 阈值 -? 查询 -r 删除
362
- 审核方式:0=全部同意, 1=按数量, 2=按比例, 3=全部拒绝
363
- 示例:group-verify.config 学生,校友,老师 -m 1 -t 2
416
+ 主指令别名:gv, gverify
417
+
418
+ 配置命令 (.config):
419
+ 选项:
420
+ -i <群号> 指定群号(私聊时必需)
421
+ -m <方式> 审核方式 (0=全部同意, 1=按数量, 2=按比例, 3=全部拒绝)
422
+ -t <阈值> 阈值参数(方式1或2时必需)
423
+ -msg <消息> 自定义提醒消息
424
+ -? 查询当前配置
425
+ -r 删除配置
426
+
427
+ 示例:
428
+ gv.config 关键词1,关键词2 -m 1 -t 2
429
+ gv.config -i 123456789 -?
430
+ gv.config -r -i 123456789
431
+
432
+ 提醒消息变量:
433
+ {user} - 用户名
434
+ {id} - 用户ID
435
+ {group} - 群号
436
+ {gname} - 群名称
437
+ {question} - 申请理由
438
+ {answer} - 答对数量/比例
439
+ {threshold} - 阈值要求
440
+ \\n - 换行符
364
441
 
365
- .approve <用户ID> - 同意加群申请 (需管理员权限)
366
- .reject <用户ID> - 拒绝加群申请 (需管理员权限)
367
- .pending - 查看待审核列表
368
- .stats [群号] - 查看统计信息
369
- .help - 显示此帮助信息
442
+ 权限说明:
443
+ - 群主/管理员权限
444
+ - koishi三级以上权限
445
+ - 私聊时必须指定群号(-i参数)
370
446
 
371
- 权限说明:管理命令需群管理员或koishi三级以上权限
372
- 别名:.cfg(配置) .accept(同意) .rej(拒绝) .stat(统计) .list(列表)`;
447
+ 其他命令:
448
+ .approve <用户ID> - 同意加群申请
449
+ .reject <用户ID> - 拒绝加群申请
450
+ .pending - 查看待审核列表
451
+ .stats [群号] - 查看统计信息`;
373
452
  });
374
453
  }
375
454
  __name(apply, "apply");
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-group-verification",
3
3
  "description": "Koishi 群组加群验证插件,支持多关键词匹配审核、多种审核方式和详细统计功能",
4
- "version": "1.0.2",
4
+ "version": "1.0.4",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
@@ -34,10 +34,10 @@
34
34
  }
35
35
  },
36
36
  "peerDependencies": {
37
- "koishi": "^4.18.7"
37
+ "koishi": "^4.15.0"
38
38
  },
39
39
  "devDependencies": {
40
- "typescript": "^5.0.0",
41
- "@types/node": "^18.0.0"
40
+ "typescript": "^4.9.0",
41
+ "@types/node": "^16.0.0"
42
42
  }
43
43
  }
package/src/index.ts CHANGED
@@ -21,6 +21,8 @@ export interface GroupVerificationConfig {
21
21
  threshold?: number // 数量阈值或比例阈值
22
22
  }
23
23
  reminderMessage: string
24
+ createdBy: string
25
+ updatedBy: string
24
26
  createdAt: Date
25
27
  updatedAt: Date
26
28
  }
@@ -58,6 +60,8 @@ export function apply(ctx: Context, config: Config) {
58
60
  reviewMethod: 'integer',
59
61
  reviewParameters: 'json',
60
62
  reminderMessage: 'string',
63
+ createdBy: 'string',
64
+ updatedBy: 'string',
61
65
  createdAt: 'date',
62
66
  updatedAt: 'date'
63
67
  }, {
@@ -110,7 +114,7 @@ export function apply(ctx: Context, config: Config) {
110
114
  const config = groupConfig[0]
111
115
 
112
116
  // 执行验证
113
- const isValid = await verifyApplication(config, message)
117
+ const { isValid, matchedCount, requiredThreshold } = await verifyApplication(config, message, session)
114
118
 
115
119
  if (isValid) {
116
120
  // 验证成功,自动同意入群
@@ -131,6 +135,18 @@ export function apply(ctx: Context, config: Config) {
131
135
  const username = session.username || '未知用户'
132
136
  const message = session.content || ''
133
137
 
138
+ // 获取群信息
139
+ let groupName = '未知群组'
140
+ try {
141
+ const guild = await session.bot.getGuild(guildId)
142
+ groupName = guild.name || groupName
143
+ } catch (error) {
144
+ // 无法获取群名称时使用默认值
145
+ }
146
+
147
+ // 执行验证获取详细信息
148
+ const { matchedCount, requiredThreshold } = await verifyApplication(config, message, session)
149
+
134
150
  // 将申请加入待审核列表
135
151
  await ctx.database.create('group_verification_pending', {
136
152
  groupId: guildId,
@@ -140,32 +156,56 @@ export function apply(ctx: Context, config: Config) {
140
156
  applyTime: new Date()
141
157
  })
142
158
 
159
+ // 替换提醒消息中的变量
160
+ let reminderMsg = config.reminderMessage
161
+ reminderMsg = reminderMsg
162
+ .replace(/{user}/g, username)
163
+ .replace(/{id}/g, userId)
164
+ .replace(/{group}/g, guildId)
165
+ .replace(/{gname}/g, groupName)
166
+ .replace(/{question}/g, message)
167
+ .replace(/{answer}/g, matchedCount.toString())
168
+ .replace(/{threshold}/g, requiredThreshold)
169
+
143
170
  // 发送提醒消息到群内
144
- const reminderMsg = config.reminderMessage || `收到新的加群申请:${username}(${userId})\n申请理由:${message}\n请管理员使用 #同意 或 #拒绝 来处理此申请`
145
171
  await ctx.broadcast([guildId], reminderMsg)
146
172
  }
147
173
 
148
174
  // 验证申请
149
- async function verifyApplication(config: GroupVerificationConfig, message: string): Promise<boolean> {
175
+ async function verifyApplication(config: GroupVerificationConfig, message: string, session: any): Promise<{isValid: boolean, matchedCount: number, requiredThreshold: string}> {
150
176
  // 统计匹配的关键词数量
151
177
  const matchedCount = config.keywords.filter(keyword =>
152
178
  message.toLowerCase().includes(keyword.toLowerCase())
153
179
  ).length
154
180
 
181
+ let isValid = false
182
+ let requiredThreshold = ''
183
+
155
184
  switch (config.reviewMethod) {
156
185
  case 0: // 全部同意
157
- return true
186
+ isValid = true
187
+ requiredThreshold = 'null'
188
+ break
158
189
  case 1: // 按数量同意
159
- return matchedCount >= (config.reviewParameters.threshold || 1)
190
+ isValid = matchedCount >= (config.reviewParameters.threshold || 1)
191
+ requiredThreshold = `${config.reviewParameters.threshold || 1}`
192
+ break
160
193
  case 2: // 按比例同意
161
194
  const ratio = matchedCount / config.keywords.length
162
195
  const requiredRatio = (config.reviewParameters.threshold || 100) / 100
163
- return ratio >= requiredRatio
196
+ isValid = ratio >= requiredRatio
197
+ requiredThreshold = `${config.reviewParameters.threshold || 100}%`
198
+ break
164
199
  case 3: // 全部拒绝
165
- return false
200
+ isValid = false
201
+ requiredThreshold = 'null'
202
+ break
166
203
  default:
167
- return false
204
+ isValid = false
205
+ requiredThreshold = 'null'
168
206
  }
207
+
208
+ return { isValid, matchedCount, requiredThreshold }
169
209
  }
170
210
 
171
211
  // 更新统计信息
@@ -210,31 +250,56 @@ export function apply(ctx: Context, config: Config) {
210
250
  }
211
251
 
212
252
  // 权限检查函数
213
- async function checkPermission(session: any, targetGroupId?: string): Promise<boolean> {
253
+ async function checkPermission(session: any, targetGroupId?: string): Promise<[boolean, string?]> {
214
254
  const groupId = targetGroupId || session.guildId
215
255
 
216
- // 检查是否为群管理员
217
- if (groupId) {
218
- try {
219
- const member = await session.bot.getGuildMember(groupId, session.userId)
220
- if (member && (member.roles?.includes('admin') || member.permissions?.includes('ADMINISTRATOR'))) {
221
- return true
222
- }
223
- } catch (error) {
224
- // 如果无法获取群成员信息,继续检查其他权限
225
- }
256
+ // 私聊情况下必须指定群号
257
+ if (!groupId) {
258
+ return [false, '请在群聊中使用此命令或使用 -i 参数指定群号']
226
259
  }
227
260
 
261
+ // 调试日志:输出权限检查信息
262
+ console.log(`[权限检查] 用户ID: ${session.userId}, 群号: ${groupId}`)
263
+ console.log(`[权限检查] Koishi权限等级: ${session.author?.authority || '未获取到'}`)
264
+
228
265
  // 检查koishi权限等级(三级及以上)
229
266
  if (session.author?.authority && session.author.authority >= 3) {
230
- return true
267
+ console.log(`[权限检查] 通过koishi权限检查: ${session.author.authority}`)
268
+ return [true]
231
269
  }
232
270
 
233
- return false
271
+ // 检查是否为群主或管理员
272
+ try {
273
+ const member = await session.bot.getGuildMember(groupId, session.userId)
274
+ console.log(`[权限检查] 获取到成员信息:`, {
275
+ roles: member?.roles,
276
+ permissions: member?.permissions
277
+ })
278
+
279
+ if (member) {
280
+ // 检查群主权限
281
+ if (member.permissions?.includes('OWNER')) {
282
+ console.log(`[权限检查] 用户是群主`)
283
+ return [true]
284
+ }
285
+ // 检查管理员权限
286
+ if (member.roles?.includes('admin') || member.permissions?.includes('ADMINISTRATOR')) {
287
+ console.log(`[权限检查] 用户是管理员`)
288
+ return [true]
289
+ }
290
+ }
291
+ } catch (error) {
292
+ console.log(`[权限检查] 获取群成员信息失败:`, error)
293
+ return [false, `无法获取群 ${groupId} 的成员信息,请确认机器人已在该群中`]
294
+ }
295
+
296
+ console.log(`[权限检查] 权限不足`)
297
+ return [false, '权限不足:需要群主/管理员权限或koishi三级以上权限']
234
298
  }
235
299
 
236
- // Create main command
300
+ // Create main command with aliases
237
301
  const groupVerify = ctx.command('group-verify', '群组验证管理命令')
302
+ .alias('gv', 'gverify')
238
303
 
239
304
  // Subcommand: configure group verification
240
305
  groupVerify
@@ -243,18 +308,27 @@ export function apply(ctx: Context, config: Config) {
243
308
  .option('groupId', '-i <groupId> 指定群号')
244
309
  .option('method', '-m <method> 审核方式 (0-3)')
245
310
  .option('threshold', '-t <threshold> 阈值参数')
311
+ .option('message', '-msg <message> 自定义提醒消息')
246
312
  .option('query', '-? 查询当前配置')
247
313
  .option('remove', '-r 删除配置')
248
314
  .action(async ({ session, options }, keywords) => {
249
315
  const targetGroupId = options.groupId || session.guildId
250
316
 
251
317
  // 权限检查
252
- if (!(await checkPermission(session, targetGroupId))) {
253
- return '权限不足'
318
+ const [hasPermission, errorMsg] = await checkPermission(session, targetGroupId)
319
+ if (!hasPermission) {
320
+ return errorMsg || '权限不足'
254
321
  }
255
322
 
256
- if (!targetGroupId) {
257
- return '请在群聊中使用此命令或使用 -i 参数指定群号'
323
+ // 获取群信息
324
+ let groupName = '未知群组'
325
+ if (targetGroupId) {
326
+ try {
327
+ const guild = await session.bot.getGuild(targetGroupId)
328
+ groupName = guild.name || groupName
329
+ } catch (error) {
330
+ // 无法获取群名称时使用默认值
331
+ }
258
332
  }
259
333
 
260
334
  // 处理删除配置
@@ -274,30 +348,47 @@ export function apply(ctx: Context, config: Config) {
274
348
  if (existingConfig.length > 0) {
275
349
  const config = existingConfig[0]
276
350
  let methodDesc = ''
351
+ let thresholdInfo = ''
277
352
  switch (config.reviewMethod) {
278
- case 0: methodDesc = '全部同意'; break
279
- case 1: methodDesc = `按数量同意 (${config.reviewParameters.threshold || 1})`; break
280
- case 2: methodDesc = `按比例同意 (${config.reviewParameters.threshold || 100}%)`; break
281
- case 3: methodDesc = '全部拒绝'; break
353
+ case 0:
354
+ methodDesc = '全部同意'
355
+ thresholdInfo = 'null'
356
+ break
357
+ case 1:
358
+ methodDesc = `按数量同意`
359
+ thresholdInfo = `${config.reviewParameters.threshold || 1}`
360
+ break
361
+ case 2:
362
+ methodDesc = `按比例同意`
363
+ thresholdInfo = `${config.reviewParameters.threshold || 100}%`
364
+ break
365
+ case 3:
366
+ methodDesc = '全部拒绝'
367
+ thresholdInfo = 'null'
368
+ break
282
369
  }
283
- return `群 ${targetGroupId} 配置:\n关键词: ${config.keywords.join(', ')}\n审核方式: ${methodDesc}`
370
+
371
+ const createTime = new Date(config.createdAt).toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })
372
+ const updateTime = new Date(config.updatedAt).toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })
373
+
374
+ return `群 ${targetGroupId} 配置:
375
+ 关键词: ${config.keywords.join(', ')}
376
+ 审核方式: ${methodDesc}
377
+ 阈值: ${thresholdInfo}
378
+ 提醒消息: ${config.reminderMessage}
379
+ 创建时间: ${createTime}
380
+ 更新时间: ${updateTime}
381
+ 创建者: ${config.createdBy}
382
+ 更新者: ${config.updatedBy}`
284
383
  } else {
285
384
  return `群 ${targetGroupId} 无验证配置`
286
385
  }
287
386
  }
288
387
 
289
388
  // 处理配置创建/更新
290
- if (!keywords) {
291
- return '请提供关键词参数,或使用 -? 查询配置,-r 删除配置'
292
- }
389
+ const keywordList = keywords ? keywords.split(',').map(k => k.trim()).filter(k => k) : []
293
390
 
294
- const keywordList = keywords.split(',').map(k => k.trim()).filter(k => k)
295
-
296
- if (keywordList.length === 0) {
297
- return '请提供有效的关键词'
298
- }
299
-
300
- // 解析审核方式
391
+ // 解析审核方式和阈值
301
392
  let reviewMethod: 0 | 1 | 2 | 3 = 0 // 默认全部同意
302
393
  let reviewParameters: { threshold?: number } = {}
303
394
 
@@ -329,29 +420,40 @@ export function apply(ctx: Context, config: Config) {
329
420
  }
330
421
  }
331
422
 
423
+ // 处理提醒消息
424
+ let reminderMessage = options.message ||
425
+ `用户 {user}({id}) 申请加入群 {gname}({group})
426
+ 申请理由:{question}
427
+ 答对情况:{answer}
428
+ 阈值要求:{threshold}
429
+ 请管理员使用 #同意 或 #拒绝 来处理此申请`
430
+
431
+ // 替换换行符
432
+ reminderMessage = reminderMessage.replace(/\\n/g, '\n')
433
+
332
434
  // Check if configuration already exists
333
435
  const existingConfig = await ctx.database.get('group_verification_config', { groupId: targetGroupId })
334
436
 
437
+ const configData = {
438
+ keywords: keywordList,
439
+ reviewMethod: reviewMethod,
440
+ reviewParameters: reviewParameters,
441
+ reminderMessage: reminderMessage,
442
+ updatedBy: session.username || session.userId,
443
+ updatedAt: new Date()
444
+ }
445
+
335
446
  if (existingConfig.length > 0) {
336
447
  // Update existing configuration
337
- await ctx.database.set('group_verification_config', { id: existingConfig[0].id }, {
338
- keywords: keywordList,
339
- reviewMethod: reviewMethod,
340
- reviewParameters: reviewParameters,
341
- reminderMessage: `New join request received. Please use #approve or #reject to handle this request`,
342
- updatedAt: new Date()
343
- })
448
+ await ctx.database.set('group_verification_config', { id: existingConfig[0].id }, configData)
344
449
  return `已更新群 ${targetGroupId} 的验证配置`
345
450
  } else {
346
451
  // Create new configuration
347
452
  await ctx.database.create('group_verification_config', {
453
+ ...configData,
348
454
  groupId: targetGroupId,
349
- keywords: keywordList,
350
- reviewMethod: reviewMethod,
351
- reviewParameters: reviewParameters,
352
- reminderMessage: `New join request received. Please use #approve or #reject to handle this request`,
353
- createdAt: new Date(),
354
- updatedAt: new Date()
455
+ createdBy: session.username || session.userId,
456
+ createdAt: new Date()
355
457
  })
356
458
  return `已为群 ${targetGroupId} 创建验证配置`
357
459
  }
@@ -486,17 +588,42 @@ export function apply(ctx: Context, config: Config) {
486
588
  .subcommand('.help', '显示帮助信息')
487
589
  .alias('帮助', 'hlp', '帮助信息')
488
590
  .action(() => {
489
- return `群组验证命令帮助:\n` +
490
- `.config [关键词] [选项] - 配置验证规则\n` +
491
- ` 选项:-i 群号 -m 方式(0-3) -t 阈值 -? 查询 -r 删除\n` +
492
- ` 审核方式:0=全部同意, 1=按数量, 2=按比例, 3=全部拒绝\n` +
493
- ` 示例:group-verify.config 学生,校友,老师 -m 1 -t 2\n\n` +
494
- `.approve <用户ID> - 同意加群申请 (需管理员权限)\n` +
495
- `.reject <用户ID> - 拒绝加群申请 (需管理员权限)\n` +
496
- `.pending - 查看待审核列表\n` +
497
- `.stats [群号] - 查看统计信息\n` +
498
- `.help - 显示此帮助信息\n\n` +
499
- `权限说明:管理命令需群管理员或koishi三级以上权限\n` +
500
- `别名:.cfg(配置) .accept(同意) .rej(拒绝) .stat(统计) .list(列表)`
591
+ return `群组验证命令帮助:
592
+ 主指令别名:gv, gverify
593
+
594
+ 配置命令 (.config):
595
+ 选项:
596
+ -i <群号> 指定群号(私聊时必需)
597
+ -m <方式> 审核方式 (0=全部同意, 1=按数量, 2=按比例, 3=全部拒绝)
598
+ -t <阈值> 阈值参数(方式1或2时必需)
599
+ -msg <消息> 自定义提醒消息
600
+ -? 查询当前配置
601
+ -r 删除配置
602
+
603
+ 示例:
604
+ gv.config 关键词1,关键词2 -m 1 -t 2
605
+ gv.config -i 123456789 -?
606
+ gv.config -r -i 123456789
607
+
608
+ 提醒消息变量:
609
+ {user} - 用户名
610
+ {id} - 用户ID
611
+ {group} - 群号
612
+ {gname} - 群名称
613
+ {question} - 申请理由
614
+ {answer} - 答对数量/比例
615
+ {threshold} - 阈值要求
616
+ \\n - 换行符
617
+
618
+ 权限说明:
619
+ - 群主/管理员权限
620
+ - koishi三级以上权限
621
+ - 私聊时必须指定群号(-i参数)
622
+
623
+ 其他命令:
624
+ .approve <用户ID> - 同意加群申请
625
+ .reject <用户ID> - 拒绝加群申请
626
+ .pending - 查看待审核列表
627
+ .stats [群号] - 查看统计信息`
501
628
  })
502
629
  }