koishi-plugin-blacklist-online 0.1.0 → 0.1.2

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/core.d.ts CHANGED
@@ -5,7 +5,7 @@ export declare function isUserAdmin(session: Session, config: PluginConfig, user
5
5
  export declare function syncBlacklist(ctx: Context, config: PluginConfig): Promise<void>;
6
6
  export declare function queueRequest(ctx: Context, type: 'ADD' | 'REMOVE' | 'CANCEL', payload: any): Promise<any>;
7
7
  export declare function processOfflineQueue(ctx: Context, config: PluginConfig): Promise<void>;
8
- export declare function checkAndHandleUser(ctx: Context, config: PluginConfig, session: Session, userId: string): Promise<boolean>;
8
+ export declare function checkAndHandleUser(ctx: Context, config: PluginConfig, session: Session, user_id: string): Promise<boolean>;
9
9
  export declare function parseUserId(input: string): string;
10
10
  export declare function scanGuild(ctx: Context, config: PluginConfig, bot: any, // 传入具体的 bot 实例
11
11
  guildId: string): Promise<{
package/lib/core.js CHANGED
@@ -68,7 +68,7 @@ async function syncBlacklist(ctx, config) {
68
68
  if (data.upserts?.length)
69
69
  await ctx.database.upsert('blacklist_users', data.upserts);
70
70
  if (data.deletes?.length)
71
- await ctx.database.remove('blacklist_users', { userId: data.deletes });
71
+ await ctx.database.remove('blacklist_users', { user_id: data.deletes });
72
72
  }
73
73
  await ctx.database.upsert('blacklist_meta', [{ key: 'sync_revision', value: newRevision }]);
74
74
  logger.info('✅ 同步完成');
@@ -146,7 +146,7 @@ async function processOfflineQueue(ctx, config) {
146
146
  }
147
147
  }
148
148
  // --- 5. 用户检查核心 ---
149
- async function checkAndHandleUser(ctx, config, session, userId) {
149
+ async function checkAndHandleUser(ctx, config, session, user_id) {
150
150
  if (!session.guildId)
151
151
  return false;
152
152
  const guildSettings = await ctx.database.get('blacklist_guild_settings', { guildId: session.guildId });
@@ -155,25 +155,25 @@ async function checkAndHandleUser(ctx, config, session, userId) {
155
155
  return false;
156
156
  // 1. 本地白名单 (最高优先级)
157
157
  const protectedSet = new Set(config.protectedUsers || []);
158
- if (protectedSet.has(userId))
158
+ if (protectedSet.has(user_id))
159
159
  return false;
160
160
  // 2. 查库
161
- const entries = await ctx.database.get('blacklist_users', { userId, disabled: false });
161
+ const entries = await ctx.database.get('blacklist_users', { user_id, disabled: false });
162
162
  if (entries.length === 0)
163
163
  return false;
164
164
  const entry = entries[0];
165
165
  const reason = entry.reason || 'QQ号黑名单';
166
166
  // 3. 查管理员
167
- if (await isUserAdmin(session, config, userId)) {
168
- logger.info(`🛡️ 跳过黑名单管理员 ${userId}`);
167
+ if (await isUserAdmin(session, config, user_id)) {
168
+ logger.info(`🛡️ 跳过黑名单管理员 ${user_id}`);
169
169
  return false;
170
170
  }
171
- logger.info(`🎯 [群: ${session.guildId}] 发现黑名单用户: ${userId} - 原因: ${reason}`);
171
+ logger.info(`🎯 [群: ${session.guildId}] 发现黑名单用户: ${user_id} - 原因: ${reason}`);
172
172
  // 获取显示名
173
- let displayName = userId;
173
+ let displayName = user_id;
174
174
  try {
175
- const member = await session.bot.getGuildMember(session.guildId, userId);
176
- displayName = member.nick || member.user?.name || userId;
175
+ const member = await session.bot.getGuildMember(session.guildId, user_id);
176
+ displayName = member.nick || member.user?.name || user_id;
177
177
  }
178
178
  catch {
179
179
  }
@@ -182,7 +182,7 @@ async function checkAndHandleUser(ctx, config, session, userId) {
182
182
  const tpl = mode === 'notify' ? config.adminNotifyMessage : config.kickNotifyMessage;
183
183
  const msg = tpl
184
184
  .replace('{user}', displayName)
185
- .replace('{userId}', userId)
185
+ .replace('{userId}', user_id)
186
186
  .replace('{reason}', reason)
187
187
  .replace('{guild}', session.guildId);
188
188
  // 引用回复
@@ -193,9 +193,9 @@ async function checkAndHandleUser(ctx, config, session, userId) {
193
193
  if (mode === 'kick' || mode === 'both') {
194
194
  for (let i = 0; i < config.retryAttempts; i++) {
195
195
  try {
196
- await session.bot.kickGuildMember(session.guildId, userId);
196
+ await session.bot.kickGuildMember(session.guildId, user_id);
197
197
  kicked = true;
198
- logger.info(`✅ [群: ${session.guildId}] 成功踢出: ${userId}`);
198
+ logger.info(`✅ [群: ${session.guildId}] 成功踢出: ${user_id}`);
199
199
  break;
200
200
  }
201
201
  catch (e) {
@@ -211,9 +211,9 @@ async function checkAndHandleUser(ctx, config, session, userId) {
211
211
  if (kicked && config.verifyKickResult) {
212
212
  await (0, exports.sleep)(2000);
213
213
  try {
214
- await session.bot.getGuildMember(session.guildId, userId);
214
+ await session.bot.getGuildMember(session.guildId, user_id);
215
215
  // 如果还能获取到,说明没踢掉
216
- logger.warn(`⚠️ [群: ${session.guildId}] 踢出验证失败,用户仍在群内: ${userId}`);
216
+ logger.warn(`⚠️ [群: ${session.guildId}] 踢出验证失败,用户仍在群内: ${user_id}`);
217
217
  }
218
218
  catch {
219
219
  // 获取不到说明踢出成功
@@ -240,7 +240,7 @@ guildId) {
240
240
  const members = await bot.getGuildMemberList(guildId);
241
241
  // 2. 获取本地黑名单缓存
242
242
  const blacklist = await ctx.database.get('blacklist_users', { disabled: false });
243
- const blacklistSet = new Set(blacklist.map(b => b.userId));
243
+ const blacklistSet = new Set(blacklist.map(b => b.user_id));
244
244
  // 3. 筛选目标 (内存操作,极快)
245
245
  const targets = members.data.filter((m) => {
246
246
  if (!m.user?.id)
package/lib/index.d.ts CHANGED
@@ -2,6 +2,6 @@ import { Context, Schema } from 'koishi';
2
2
  import { PluginConfig } from './types';
3
3
  export declare const name = "blacklist-online";
4
4
  export declare const inject: string[];
5
- export declare const usage = "\n## \u529F\u80FD\u8BF4\u660E\n\u4E00\u4E2A\u5F3A\u5927\u7684\u3001\u57FA\u4E8E\u6570\u636E\u5E93\u7684\u7FA4\u7EC4\u9ED1\u540D\u5355\u7BA1\u7406\u63D2\u4EF6\u3002\n- **\u6570\u636E\u5E93\u9A71\u52A8**: QQ\u53F7\u9ED1\u540D\u5355\u5B58\u50A8\u5728\u6570\u636E\u5E93\u4E2D\uFF0C\u53EF\u901A\u8FC7\u6307\u4EE4\u52A8\u6001\u589E\u5220\uFF0C\u652F\u6301\u64CD\u4F5C\u8FFD\u6EAF\u3002\n- **\u53D7\u4FDD\u62A4\u540D\u5355**: \u914D\u7F6E\u4E2D\u7684\u7528\u6237\u65E0\u6CD5\u88AB\u62C9\u9ED1\u3002\n- **\u7533\u8BF7/\u5BA1\u6279\u6D41\u7A0B**: \u666E\u901A\u7FA4\u7BA1\u7406\u53EF\u63D0\u4EA4\u62C9\u9ED1\u7533\u8BF7\uFF0C\u7531\u673A\u5668\u4EBA\u7BA1\u7406\u5458\u5BA1\u6279\uFF0C\u6240\u6709\u6D41\u7A0B\u81EA\u52A8\u5316\u901A\u77E5\u3002\n- **\u5206\u7FA4\u7BA1\u7406**: \u53EF\u4E3A\u6BCF\u4E2A\u7FA4\u72EC\u7ACB\u8BBE\u7F6E\u9ED1\u540D\u5355\u5904\u7406\u6A21\u5F0F\u3002\n- **\u6635\u79F0\u9ED1\u540D\u5355**: \u652F\u6301\u914D\u7F6E\u9759\u6001\u7684\u6635\u79F0\u5173\u952E\u8BCD\u9ED1\u540D\u5355\uFF0C\u5E76\u6709\u603B\u5F00\u5173\u63A7\u5236\u3002\n- **\u5165\u7FA4\u626B\u63CF**: \u53EF\u914D\u7F6E\u673A\u5668\u4EBA\u5728\u52A0\u5165\u65B0\u7FA4\u7EC4\u65F6\uFF0C\u81EA\u52A8\u626B\u63CF\u7FA4\u5185\u73B0\u6709\u6210\u5458\u3002\n- **\u5EF6\u8FDF\u68C0\u67E5**: \u65B0\u6210\u5458\u52A0\u5165\u540E\uFF0C\u53EF\u914D\u7F6E\u5EF6\u8FDF\u53CA\u5468\u671F\u6027\u6635\u79F0\u68C0\u67E5\uFF0C\u9632\u6B62\u5176\u4FEE\u6539\u6635\u79F0\u7ED5\u8FC7\u68C0\u6D4B\u3002\n- **\u81EA\u52A8\u62D2\u7EDD**: \u81EA\u52A8\u62D2\u7EDD\u6570\u636E\u5E93\u9ED1\u540D\u5355\u7528\u6237\u7684\u52A0\u7FA4\u7533\u8BF7\u3002\n- **\u624B\u52A8\u626B\u63CF**: \u63D0\u4F9B\u6307\u4EE4\u624B\u52A8\u626B\u63CF\u5F53\u524D\u6216\u5168\u90E8\u7FA4\u7EC4\u3002\n- **\u6743\u9650\u63A7\u5236**: \u6240\u6709\u6307\u4EE4\u5747\u6709\u6743\u9650\u7B49\u7EA7\u63A7\u5236\u3002\n";
5
+ export declare const usage = "\n## \u529F\u80FD\u8BF4\u660E\n\u4E00\u4E2A\u5F3A\u5927\u7684\u3001\u57FA\u4E8E\u6570\u636E\u5E93\u7684\u7FA4\u7EC4\u9ED1\u540D\u5355\u7BA1\u7406\u63D2\u4EF6\u3002\n- **\u53D7\u4FDD\u62A4\u540D\u5355**: \u914D\u7F6E\u4E2D\u7684\u7528\u6237\u65E0\u6CD5\u88AB\u62C9\u9ED1\u3002\n- **\u5206\u7FA4\u7BA1\u7406**: \u53EF\u4E3A\u6BCF\u4E2A\u7FA4\u72EC\u7ACB\u8BBE\u7F6E\u9ED1\u540D\u5355\u5904\u7406\u6A21\u5F0F\u3002\n- **\u5165\u7FA4\u626B\u63CF**: \u53EF\u914D\u7F6E\u673A\u5668\u4EBA\u5728\u52A0\u5165\u65B0\u7FA4\u7EC4\u65F6\uFF0C\u81EA\u52A8\u626B\u63CF\u7FA4\u5185\u73B0\u6709\u6210\u5458\u3002\n- **\u81EA\u52A8\u62D2\u7EDD**: \u81EA\u52A8\u62D2\u7EDD\u6570\u636E\u5E93\u9ED1\u540D\u5355\u7528\u6237\u7684\u52A0\u7FA4\u7533\u8BF7\u3002\n- **\u624B\u52A8\u626B\u63CF**: \u63D0\u4F9B\u6307\u4EE4\u624B\u52A8\u626B\u63CF\u5F53\u524D\u6216\u5168\u90E8\u7FA4\u7EC4\u3002\n- **\u6743\u9650\u63A7\u5236**: \u6240\u6709\u6307\u4EE4\u5747\u6709\u6743\u9650\u7B49\u7EA7\u63A7\u5236\u3002\n";
6
6
  export declare const Config: Schema<PluginConfig>;
7
7
  export declare function apply(ctx: Context, config: PluginConfig): void;
package/lib/index.js CHANGED
@@ -10,13 +10,9 @@ exports.inject = ['database', 'http'];
10
10
  exports.usage = `
11
11
  ## 功能说明
12
12
  一个强大的、基于数据库的群组黑名单管理插件。
13
- - **数据库驱动**: QQ号黑名单存储在数据库中,可通过指令动态增删,支持操作追溯。
14
13
  - **受保护名单**: 配置中的用户无法被拉黑。
15
- - **申请/审批流程**: 普通群管理可提交拉黑申请,由机器人管理员审批,所有流程自动化通知。
16
14
  - **分群管理**: 可为每个群独立设置黑名单处理模式。
17
- - **昵称黑名单**: 支持配置静态的昵称关键词黑名单,并有总开关控制。
18
15
  - **入群扫描**: 可配置机器人在加入新群组时,自动扫描群内现有成员。
19
- - **延迟检查**: 新成员加入后,可配置延迟及周期性昵称检查,防止其修改昵称绕过检测。
20
16
  - **自动拒绝**: 自动拒绝数据库黑名单用户的加群申请。
21
17
  - **手动扫描**: 提供指令手动扫描当前或全部群组。
22
18
  - **权限控制**: 所有指令均有权限等级控制。
@@ -54,8 +50,13 @@ function apply(ctx, config) {
54
50
  const logger = ctx.logger('blacklist-online');
55
51
  // 1. 扩展数据库
56
52
  ctx.model.extend('blacklist_users', {
57
- userId: 'string', reason: 'string', disabled: { type: 'boolean', initial: false }, updatedAt: 'timestamp'
58
- }, { primary: 'userId' });
53
+ user_id: 'string',
54
+ reason: 'string',
55
+ disabled: { type: 'boolean', initial: false },
56
+ operator_id: 'string',
57
+ source_id: 'string',
58
+ updated_at: 'timestamp'
59
+ }, { primary: 'user_id' });
59
60
  ctx.model.extend('blacklist_request_queue', {
60
61
  id: 'string', type: 'string', payload: 'json', createdAt: 'timestamp', retryCount: 'unsigned'
61
62
  }, { primary: 'id' });
@@ -94,7 +95,7 @@ function apply(ctx, config) {
94
95
  if (config.protectedUsers.includes(session.userId))
95
96
  return;
96
97
  // 查库
97
- const entries = await ctx.database.get('blacklist_users', { userId: session.userId, disabled: false });
98
+ const entries = await ctx.database.get('blacklist_users', { user_id: session.userId, disabled: false });
98
99
  if (entries.length > 0) {
99
100
  try {
100
101
  await session.bot.handleGuildRequest(session.messageId, false, config.rejectionMessage);
package/lib/types.d.ts CHANGED
@@ -16,11 +16,12 @@ export interface PluginConfig {
16
16
  autoRejectNotifyMessage: string;
17
17
  }
18
18
  export interface BlacklistEntry {
19
- userId: string;
19
+ user_id: string;
20
20
  reason: string;
21
- operatorId?: string;
21
+ operator_id?: string;
22
+ source_id?: string;
22
23
  disabled: boolean;
23
- updatedAt: Date;
24
+ updated_at: Date;
24
25
  }
25
26
  export interface OfflineRequest {
26
27
  id: string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-blacklist-online",
3
3
  "description": "自用插件",
4
- "version": "0.1.0",
4
+ "version": "0.1.2",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [