@nestim/koishi-plugin-qq-group-manager 0.1.3 → 0.1.5
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/commands.js +4 -46
- package/lib/index.d.ts +1 -0
- package/lib/index.js +3 -2
- package/lib/service.d.ts +6 -1
- package/lib/service.js +136 -34
- package/package.json +1 -1
package/lib/commands.js
CHANGED
|
@@ -29,16 +29,6 @@ function registerCommands(ctx, service, config) {
|
|
|
29
29
|
return result;
|
|
30
30
|
});
|
|
31
31
|
const root = ctx.command(config.command, 'QQ群管理命令入口');
|
|
32
|
-
root
|
|
33
|
-
.subcommand('ping', '检查插件是否可用')
|
|
34
|
-
.action(async ({ session }) => {
|
|
35
|
-
const auth = await service.authorizeCommand('ping', session);
|
|
36
|
-
if (!auth.ok)
|
|
37
|
-
return auth.userMessage ?? '权限不足或上下文不符合要求。';
|
|
38
|
-
const result = { ok: true, message: 'qq-group-manager 已加载。' };
|
|
39
|
-
service.logCommandResult('ping', result, session);
|
|
40
|
-
return styleText(result.message, config);
|
|
41
|
-
});
|
|
42
32
|
root
|
|
43
33
|
.subcommand('查图', '识图调试:查看本条消息中被识别的图片信息')
|
|
44
34
|
.action(async ({ session }) => {
|
|
@@ -66,19 +56,6 @@ function registerCommands(ctx, service, config) {
|
|
|
66
56
|
}
|
|
67
57
|
return styleText('识图诊断:\n' + lines.join('\n'), config);
|
|
68
58
|
});
|
|
69
|
-
root
|
|
70
|
-
.subcommand('plan <groupId:string>', '生成演练动作计划')
|
|
71
|
-
.option('reason', '-r <reason:string> 计划原因')
|
|
72
|
-
.action(async ({ session, options }, groupId) => {
|
|
73
|
-
if (!groupId)
|
|
74
|
-
return '请提供群号。';
|
|
75
|
-
const auth = await service.authorizeCommand('plan', session);
|
|
76
|
-
if (!auth.ok)
|
|
77
|
-
return auth.userMessage ?? '权限不足或上下文不符合要求。';
|
|
78
|
-
const result = await service.planDemoAction(groupId, options.reason);
|
|
79
|
-
service.logCommandResult('plan', result, session, { groupId });
|
|
80
|
-
return formatAction(result, config);
|
|
81
|
-
});
|
|
82
59
|
root
|
|
83
60
|
.subcommand('kick <target:string>', '踢出群成员')
|
|
84
61
|
.option('reject', '-r 拒绝再次加群请求')
|
|
@@ -128,17 +105,16 @@ function registerCommands(ctx, service, config) {
|
|
|
128
105
|
return formatAction(result, config, displayTarget);
|
|
129
106
|
});
|
|
130
107
|
root
|
|
131
|
-
.subcommand('gag [target:string]', '
|
|
132
|
-
.alias('
|
|
133
|
-
.alias('口气')
|
|
108
|
+
.subcommand('gag [target:string]', '自我约束(随机 1~60 分钟禁言)')
|
|
109
|
+
.alias('自我约束')
|
|
134
110
|
.option('reason', '-r <reason:string> 操作原因')
|
|
135
111
|
.action(async ({ session, options }, target) => {
|
|
136
112
|
if (!config.enableSelfGag)
|
|
137
|
-
return '
|
|
113
|
+
return '自我约束功能未启用。';
|
|
138
114
|
if (!session?.userId)
|
|
139
115
|
return '无法识别当前账号。';
|
|
140
116
|
if (config.allowedUserIds.includes(session.userId))
|
|
141
|
-
return '喵~
|
|
117
|
+
return '喵~ 白名单用户不参与自我约束。';
|
|
142
118
|
const resolvedTarget = target || session.userId;
|
|
143
119
|
if (await service.shouldSelfGag(session, resolvedTarget)) {
|
|
144
120
|
const result = await service.selfGag(session, 'gag-trigger');
|
|
@@ -191,22 +167,4 @@ function registerCommands(ctx, service, config) {
|
|
|
191
167
|
const displayTarget = await service.formatTargetDisplay(session, result.plan?.targetId, target);
|
|
192
168
|
return formatAction(result, config, displayTarget);
|
|
193
169
|
});
|
|
194
|
-
root
|
|
195
|
-
.subcommand('审核 <code:string> <state:string>', '审核入群申请(同意/拒绝)')
|
|
196
|
-
.option('reason', '-r <reason:string> 审核理由')
|
|
197
|
-
.action(async ({ session, options }, code, state) => {
|
|
198
|
-
if (!code || !state)
|
|
199
|
-
return '请提供审核编号与状态(同意/拒绝)。';
|
|
200
|
-
const auth = await service.authorizeCommand('review-join-request', session);
|
|
201
|
-
if (!auth.ok)
|
|
202
|
-
return auth.userMessage ?? '权限不足或上下文不符合要求。';
|
|
203
|
-
const normalized = state.trim().toLowerCase();
|
|
204
|
-
const approve = ['同意', '通过', '放行', '批准', 'approve', 'pass', 'ok', 'yes'].includes(normalized);
|
|
205
|
-
const reject = ['拒绝', '驳回', 'deny', 'reject', 'no', 'refuse'].includes(normalized);
|
|
206
|
-
if (!approve && !reject)
|
|
207
|
-
return '状态仅支持:同意/拒绝。';
|
|
208
|
-
const result = await service.reviewJoinRequestDecision(session, code, approve, options.reason);
|
|
209
|
-
service.logCommandResult('review-join-request', result, session, { code, approve, source: 'command' });
|
|
210
|
-
return formatAction(result, config);
|
|
211
|
-
});
|
|
212
170
|
}
|
package/lib/index.d.ts
CHANGED
|
@@ -94,6 +94,7 @@ export interface GroupRule {
|
|
|
94
94
|
autoKickEnabled?: boolean;
|
|
95
95
|
autoKickThreshold?: number;
|
|
96
96
|
autoViolationWindowMinutes?: number;
|
|
97
|
+
enableJoinRequestReview?: boolean;
|
|
97
98
|
}
|
|
98
99
|
export declare const Config: Schema<Config>;
|
|
99
100
|
export declare function apply(ctx: Context, config: Config): void;
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Config = exports.inject = exports.name = void 0;
|
|
4
4
|
exports.apply = apply;
|
|
@@ -42,6 +42,7 @@ exports.Config = koishi_1.Schema.intersect([
|
|
|
42
42
|
autoKickEnabled: koishi_1.Schema.boolean().description('该群是否启用自动踢人(留空则跟随全局设置)。'),
|
|
43
43
|
autoKickThreshold: koishi_1.Schema.natural().description('该群触发自动踢人的违规次数(留空则跟随全局设置)。'),
|
|
44
44
|
autoViolationWindowMinutes: koishi_1.Schema.natural().description('该群违规计数统计窗口(分钟,留空则跟随全局设置)。'),
|
|
45
|
+
enableJoinRequestReview: koishi_1.Schema.boolean().description('该群是否启用入群审核(留空则跟随全局设置)。'),
|
|
45
46
|
})).role('table').default([]).description('按群覆盖消息管控策略(未命中群号时使用全局默认)。'),
|
|
46
47
|
}).description('消息管控'),
|
|
47
48
|
koishi_1.Schema.object({
|
|
@@ -54,7 +55,7 @@ exports.Config = koishi_1.Schema.intersect([
|
|
|
54
55
|
}).description('自动管控'),
|
|
55
56
|
koishi_1.Schema.object({
|
|
56
57
|
enableMemory: koishi_1.Schema.boolean().default(true).description('启用记忆库:群内发送 [记忆]+内容 保存到 Memory.md,[记忆查询]/[记忆删除] 管理,AI 回复可引用。'),
|
|
57
|
-
memoryFileName: koishi_1.Schema.string().default('Memory.md').description('记忆库文件名(保存在 Koishi
|
|
58
|
+
memoryFileName: koishi_1.Schema.string().default('Memory.md').description('记忆库文件名(保存在 Koishi 数据目录)。请直接使用控制台左侧「探索器 Explorer」打开该文件查看/编辑记忆库内容。'),
|
|
58
59
|
memoryInAi: koishi_1.Schema.boolean().default(true).description('AI 回复/识图时是否参考记忆库内容。'),
|
|
59
60
|
}).description('记忆库'),
|
|
60
61
|
koishi_1.Schema.object({
|
package/lib/service.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import { Context, Service, Session } from 'koishi';
|
|
2
2
|
import type { Config } from './index';
|
|
3
3
|
import type { ActionResult, AuthorizationResult, MuteParseResult } from './types';
|
|
4
4
|
declare module 'koishi' {
|
|
@@ -139,6 +139,8 @@ export declare class QQGroupManagerService extends Service {
|
|
|
139
139
|
private toGroupId;
|
|
140
140
|
private getOneBotApi;
|
|
141
141
|
private extractTextForFilter;
|
|
142
|
+
private hasTextContent;
|
|
143
|
+
private hasImageOrFace;
|
|
142
144
|
private hasCardMessage;
|
|
143
145
|
private hasForwardMessage;
|
|
144
146
|
private normalizeGuildId;
|
|
@@ -154,6 +156,9 @@ export declare class QQGroupManagerService extends Service {
|
|
|
154
156
|
private generateJoinRequestCode;
|
|
155
157
|
private parseJoinRequestReviewText;
|
|
156
158
|
private handleJoinRequestReviewMessage;
|
|
159
|
+
private resolveJoinReviewEnabled;
|
|
160
|
+
private fetchStrangerInfo;
|
|
161
|
+
private buildJoinRequestPrompt;
|
|
157
162
|
private handleGuildMemberRequest;
|
|
158
163
|
reviewJoinRequestDecision(session: Session, code: string, approve: boolean, reason?: string): Promise<ActionResult>;
|
|
159
164
|
formatTargetDisplay(session: Session | undefined, targetId?: string, rawTarget?: string): Promise<string>;
|
package/lib/service.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
@@ -1012,9 +1012,16 @@ class QQGroupManagerService extends koishi_1.Service {
|
|
|
1012
1012
|
const cqList = content.match(cqPattern) ?? [];
|
|
1013
1013
|
for (const chunk of cqList) {
|
|
1014
1014
|
const match = chunk.match(/(?:url|src)=([^,\]]+)/i);
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1015
|
+
let value = match ? decodeURIComponent(match[1].trim()) : '';
|
|
1016
|
+
if (!this.isImageSendableUrl(value)) {
|
|
1017
|
+
// 部分适配器把 url 放在 file 字段
|
|
1018
|
+
const fm = chunk.match(/file=([^,\]]+)/i);
|
|
1019
|
+
if (fm) {
|
|
1020
|
+
const f = decodeURIComponent(fm[1].trim());
|
|
1021
|
+
if (this.isImageSendableUrl(f))
|
|
1022
|
+
value = f;
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1018
1025
|
if (!this.isImageSendableUrl(value))
|
|
1019
1026
|
continue;
|
|
1020
1027
|
urls.push(value);
|
|
@@ -1738,7 +1745,7 @@ class QQGroupManagerService extends koishi_1.Service {
|
|
|
1738
1745
|
thresholdMode,
|
|
1739
1746
|
focusText: (directMention || followupForce || relatedContextFollowup) ? (text || '@bot') : undefined,
|
|
1740
1747
|
focusUserId: (directMention || followupForce || relatedContextFollowup) ? session.userId : undefined,
|
|
1741
|
-
focusImages:
|
|
1748
|
+
focusImages: messageImages,
|
|
1742
1749
|
focusUserName: (directMention || followupForce || relatedContextFollowup) ? this.getDisplayName(session) : undefined,
|
|
1743
1750
|
topicTokens: thresholdMode ? topicTokens : undefined,
|
|
1744
1751
|
selectedRecord,
|
|
@@ -2598,6 +2605,23 @@ class QQGroupManagerService extends koishi_1.Service {
|
|
|
2598
2605
|
const raw = (session.content ?? '').replace(/\[CQ:[^\]]+\]/g, ' ');
|
|
2599
2606
|
return raw.trim();
|
|
2600
2607
|
}
|
|
2608
|
+
hasTextContent(session) {
|
|
2609
|
+
const text = this.extractTextForFilter(session);
|
|
2610
|
+
if (text)
|
|
2611
|
+
return true;
|
|
2612
|
+
// 有的适配器把图片/表情放在 elements 里,content 可能没文字;检查是否有文字元素
|
|
2613
|
+
for (const el of session.elements ?? []) {
|
|
2614
|
+
if (el.type === 'text' && String(el.text ?? el.content ?? '').trim())
|
|
2615
|
+
return true;
|
|
2616
|
+
}
|
|
2617
|
+
return false;
|
|
2618
|
+
}
|
|
2619
|
+
hasImageOrFace(session) {
|
|
2620
|
+
const content = session.content ?? '';
|
|
2621
|
+
if (/\[CQ:(image|face|record|video|flash),/i.test(content))
|
|
2622
|
+
return true;
|
|
2623
|
+
return (session.elements ?? []).some((el) => el.type === 'image' || el.type === 'face' || el.type === 'record' || el.type === 'video' || el.type === 'flash');
|
|
2624
|
+
}
|
|
2601
2625
|
hasCardMessage(session) {
|
|
2602
2626
|
const content = session.content ?? '';
|
|
2603
2627
|
if (/\[CQ:(json|xml),/i.test(content))
|
|
@@ -2651,6 +2675,10 @@ class QQGroupManagerService extends koishi_1.Service {
|
|
|
2651
2675
|
};
|
|
2652
2676
|
}
|
|
2653
2677
|
detectViolation(session, policy) {
|
|
2678
|
+
// 防误判:纯图片/表情/贴纸(无实际文字内容)的消息不作为违规处理,避免表情包被当成违禁词
|
|
2679
|
+
if (this.hasImageOrFace(session) && !this.hasTextContent(session)) {
|
|
2680
|
+
return null;
|
|
2681
|
+
}
|
|
2654
2682
|
if (policy.blockCardMessage && this.hasCardMessage(session)) {
|
|
2655
2683
|
return { type: 'card', detail: '检测到卡片消息(json/xml)' };
|
|
2656
2684
|
}
|
|
@@ -2841,21 +2869,24 @@ class QQGroupManagerService extends koishi_1.Service {
|
|
|
2841
2869
|
return `${Date.now().toString(36).toUpperCase().slice(-6)}`;
|
|
2842
2870
|
}
|
|
2843
2871
|
parseJoinRequestReviewText(text) {
|
|
2844
|
-
|
|
2872
|
+
let source = String(text).trim();
|
|
2845
2873
|
if (!source)
|
|
2846
2874
|
return null;
|
|
2847
|
-
|
|
2875
|
+
// 去掉可能的命令前缀(如 [bot])
|
|
2876
|
+
source = source.replace(/^\[[^\]]+\]\s*/, '').trim();
|
|
2877
|
+
// 支持 同意/拒绝 [编号] [理由](编号可省略)
|
|
2878
|
+
const approveMatch = source.match(/^(同意|通过|放行|批准|approve|ok|yes)\s*(?:入群|申请)?\s*#?([A-Za-z0-9]{4,12})?\s*([\s\S]*)$/i);
|
|
2848
2879
|
if (approveMatch) {
|
|
2849
|
-
return { approve: true, code: approveMatch[2].toUpperCase(), reason: (approveMatch[3] || '').trim() };
|
|
2880
|
+
return { approve: true, code: approveMatch[2] ? approveMatch[2].toUpperCase() : '', reason: (approveMatch[3] || '').trim() };
|
|
2850
2881
|
}
|
|
2851
|
-
const rejectMatch = source.match(/^(拒绝|驳回|拒|deny|reject)\s*(?:入群|申请)?\s*#?([A-Za-z0-9]{4,12})(
|
|
2882
|
+
const rejectMatch = source.match(/^(拒绝|驳回|拒|deny|reject|no|refuse)\s*(?:入群|申请)?\s*#?([A-Za-z0-9]{4,12})?\s*([\s\S]*)$/i);
|
|
2852
2883
|
if (rejectMatch) {
|
|
2853
|
-
return { approve: false, code: rejectMatch[2].toUpperCase(), reason: (rejectMatch[3] || '').trim() };
|
|
2884
|
+
return { approve: false, code: rejectMatch[2] ? rejectMatch[2].toUpperCase() : '', reason: (rejectMatch[3] || '').trim() };
|
|
2854
2885
|
}
|
|
2855
2886
|
return null;
|
|
2856
2887
|
}
|
|
2857
2888
|
async handleJoinRequestReviewMessage(session) {
|
|
2858
|
-
if (!this.
|
|
2889
|
+
if (!this.resolveJoinReviewEnabled(session))
|
|
2859
2890
|
return false;
|
|
2860
2891
|
if (session.platform !== 'onebot' || !session.guildId)
|
|
2861
2892
|
return false;
|
|
@@ -2870,8 +2901,49 @@ class QQGroupManagerService extends koishi_1.Service {
|
|
|
2870
2901
|
await session.send(this.styleText(result.message));
|
|
2871
2902
|
return true;
|
|
2872
2903
|
}
|
|
2904
|
+
resolveJoinReviewEnabled(session) {
|
|
2905
|
+
const guildId = this.normalizeGuildId(session?.guildId);
|
|
2906
|
+
const rule = this.config.groupRules?.find((item) => this.normalizeGuildId(item.guildId) === guildId);
|
|
2907
|
+
if (typeof rule?.enableJoinRequestReview === 'boolean')
|
|
2908
|
+
return rule.enableJoinRequestReview;
|
|
2909
|
+
return !!this.config.enableJoinRequestReview;
|
|
2910
|
+
}
|
|
2911
|
+
async fetchStrangerInfo(bot, userId) {
|
|
2912
|
+
if (!bot || !userId)
|
|
2913
|
+
return null;
|
|
2914
|
+
// 兼容不同 OneBot 适配器的方法命名
|
|
2915
|
+
try {
|
|
2916
|
+
if (typeof bot.getStrangerInfo === 'function')
|
|
2917
|
+
return await bot.getStrangerInfo(userId, true);
|
|
2918
|
+
}
|
|
2919
|
+
catch { /* ignore */ }
|
|
2920
|
+
try {
|
|
2921
|
+
if (typeof bot.get_stranger_info === 'function')
|
|
2922
|
+
return await bot.get_stranger_info(userId, true);
|
|
2923
|
+
}
|
|
2924
|
+
catch { /* ignore */ }
|
|
2925
|
+
return null;
|
|
2926
|
+
}
|
|
2927
|
+
buildJoinRequestPrompt(applicant, extra) {
|
|
2928
|
+
const lines = [
|
|
2929
|
+
'检测到新的入群申请,请管理员审核:',
|
|
2930
|
+
`QQ号:${applicant.userId}`,
|
|
2931
|
+
];
|
|
2932
|
+
if (extra?.nickname)
|
|
2933
|
+
lines.push(`昵称:${extra.nickname}`);
|
|
2934
|
+
if (extra?.sex)
|
|
2935
|
+
lines.push(`性别:${extra.sex}`);
|
|
2936
|
+
if (extra?.age !== undefined && extra.age !== '')
|
|
2937
|
+
lines.push(`年龄:${extra.age}`);
|
|
2938
|
+
if (extra?.level)
|
|
2939
|
+
lines.push(`QQ等级:${extra.level}`);
|
|
2940
|
+
lines.push(`验证信息:${applicant.comment || '(无)'}`);
|
|
2941
|
+
lines.push(`同意:${this.config.command} 同意 [理由]`);
|
|
2942
|
+
lines.push(`拒绝:${this.config.command} 拒绝 [理由]`);
|
|
2943
|
+
return lines.join('\n');
|
|
2944
|
+
}
|
|
2873
2945
|
async handleGuildMemberRequest(session) {
|
|
2874
|
-
if (!this.
|
|
2946
|
+
if (!this.resolveJoinReviewEnabled(session))
|
|
2875
2947
|
return;
|
|
2876
2948
|
if (!this.isPlatformAllowed(session.platform))
|
|
2877
2949
|
return;
|
|
@@ -2893,36 +2965,66 @@ class QQGroupManagerService extends koishi_1.Service {
|
|
|
2893
2965
|
};
|
|
2894
2966
|
this.pendingJoinRequests.set(code, item);
|
|
2895
2967
|
this.pendingJoinRequestFlags.set(item.flag, code);
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2968
|
+
// 尽力获取申请者信息(昵称/性别/年龄/等级/头像)
|
|
2969
|
+
let extra = {};
|
|
2970
|
+
const bot = this.getOneBotApi(session);
|
|
2971
|
+
const info = await this.fetchStrangerInfo(bot, session.userId);
|
|
2972
|
+
if (info) {
|
|
2973
|
+
const nickname = info.nickname || info.card || info.name || '';
|
|
2974
|
+
let sex = info.sex || info.gender || '';
|
|
2975
|
+
if (sex === 'male')
|
|
2976
|
+
sex = '男';
|
|
2977
|
+
else if (sex === 'female')
|
|
2978
|
+
sex = '女';
|
|
2979
|
+
else if (sex === 'unknown' || sex === '')
|
|
2980
|
+
sex = '未知';
|
|
2981
|
+
const level = (info.level !== undefined && info.level !== null) ? String(info.level) : '';
|
|
2982
|
+
extra = {
|
|
2983
|
+
nickname,
|
|
2984
|
+
sex: sex || '',
|
|
2985
|
+
age: info.age,
|
|
2986
|
+
level,
|
|
2987
|
+
avatarUrl: `https://q1.qlogo.cn/g?b=qq&nk=${encodeURIComponent(session.userId)}&s=640`,
|
|
2988
|
+
};
|
|
2989
|
+
}
|
|
2990
|
+
const prompt = this.buildJoinRequestPrompt(item, extra);
|
|
2905
2991
|
try {
|
|
2906
|
-
|
|
2907
|
-
|
|
2992
|
+
if (extra?.avatarUrl) {
|
|
2993
|
+
// 直接把头像图片发到群里,而不是给链接
|
|
2994
|
+
await session.send([koishi_1.h.text(this.styleText(prompt)), koishi_1.h.image(extra.avatarUrl)]);
|
|
2995
|
+
}
|
|
2996
|
+
else {
|
|
2997
|
+
await session.send(this.styleText(prompt));
|
|
2998
|
+
}
|
|
2999
|
+
this.logCommandResult('join-request', { ok: true, message: 'join request notice sent' }, session, { target: item.userId });
|
|
2908
3000
|
}
|
|
2909
3001
|
catch (error) {
|
|
2910
|
-
this.logCommandResult('join-request', { ok: false, message: `join request notice failed: ${String(error)}` }, session, {
|
|
3002
|
+
this.logCommandResult('join-request', { ok: false, message: `join request notice failed: ${String(error)}` }, session, { target: item.userId });
|
|
2911
3003
|
}
|
|
2912
3004
|
}
|
|
2913
3005
|
async reviewJoinRequestDecision(session, code, approve, reason) {
|
|
2914
3006
|
this.cleanupPendingJoinRequests();
|
|
2915
|
-
|
|
2916
|
-
const
|
|
2917
|
-
if (
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
3007
|
+
let item;
|
|
3008
|
+
const key = (code || '').trim().toUpperCase();
|
|
3009
|
+
if (key) {
|
|
3010
|
+
item = this.pendingJoinRequests.get(key);
|
|
3011
|
+
if (!item)
|
|
3012
|
+
return { ok: false, message: `未找到审核编号 ${key},可能已处理或已过期。` };
|
|
3013
|
+
if (session.guildId !== item.guildId)
|
|
3014
|
+
return { ok: false, message: `审核编号 ${key} 不属于当前群。` };
|
|
3015
|
+
}
|
|
3016
|
+
else {
|
|
3017
|
+
// 无编号:取当前群最近一条待审核申请
|
|
3018
|
+
const candidates = [...this.pendingJoinRequests.values()].filter((x) => x.guildId === session.guildId);
|
|
3019
|
+
if (!candidates.length)
|
|
3020
|
+
return { ok: false, message: '当前没有待审核的入群申请。' };
|
|
3021
|
+
item = candidates[candidates.length - 1];
|
|
3022
|
+
}
|
|
2921
3023
|
const plan = {
|
|
2922
3024
|
action: approve ? 'approve-join-request' : 'reject-join-request',
|
|
2923
3025
|
groupId: item.guildId,
|
|
2924
3026
|
targetId: item.userId,
|
|
2925
|
-
reason:
|
|
3027
|
+
reason: `${reason || ''}`,
|
|
2926
3028
|
};
|
|
2927
3029
|
if (this.config.dryRun)
|
|
2928
3030
|
return this.createDryRunResult(plan);
|
|
@@ -2932,13 +3034,13 @@ class QQGroupManagerService extends koishi_1.Service {
|
|
|
2932
3034
|
}
|
|
2933
3035
|
try {
|
|
2934
3036
|
await bot.handleGuildMemberRequest(item.flag, approve, reason || '');
|
|
2935
|
-
this.pendingJoinRequests.delete(
|
|
3037
|
+
this.pendingJoinRequests.delete(item.code);
|
|
2936
3038
|
this.pendingJoinRequestFlags.delete(item.flag);
|
|
2937
3039
|
return {
|
|
2938
3040
|
ok: true,
|
|
2939
3041
|
message: approve
|
|
2940
|
-
? `已放行入群申请:${item.userId}
|
|
2941
|
-
: `已拒绝入群申请:${item.userId}
|
|
3042
|
+
? `已放行入群申请:${item.userId}`
|
|
3043
|
+
: `已拒绝入群申请:${item.userId}`,
|
|
2942
3044
|
plan,
|
|
2943
3045
|
};
|
|
2944
3046
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nestim/koishi-plugin-qq-group-manager",
|
|
3
3
|
"description": "Koishi QQ群管理插件(OneBot/LLOneBot):群管命令、权限校验、图片菜单、状态卡片、复读、AI群聊回复、记忆库、识图与自动管控(禁言/踢人)。",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.5",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
7
7
|
"files": [
|