mioku-plugin-admin 2.3.5 → 3.0.1
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/commands/group.ts +463 -473
- package/commands/notice.ts +3 -3
- package/commands/personal.ts +234 -276
- package/commands/verify.ts +325 -308
- package/config.ts +29 -17
- package/index.ts +5 -7
- package/notify/index.ts +110 -140
- package/notify/welcome.ts +52 -44
- package/package.json +4 -283
- package/skills/group.ts +87 -143
- package/skills/message-image.ts +8 -9
- package/skills/personal.ts +72 -98
- package/verify/chiral.ts +4 -4
- package/verify/index.ts +59 -45
- package/verify/number.ts +4 -4
- package/verify/reaction.ts +62 -14
- package/verify/state.ts +1 -1
- package/verify/types.ts +18 -8
package/commands/verify.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
Bot,
|
|
3
|
+
CommandDefinition,
|
|
4
|
+
CommandExecutionContext,
|
|
5
|
+
MessageEvent,
|
|
6
|
+
MiokuContext,
|
|
7
|
+
} from "mioku";
|
|
2
8
|
import { extractImageUrls, getAtUserId, getMemberRole } from "../config";
|
|
3
9
|
import {
|
|
4
10
|
getGroupVerifyConfig,
|
|
@@ -17,7 +23,7 @@ import {
|
|
|
17
23
|
} from "../utils/prompt-image-store";
|
|
18
24
|
|
|
19
25
|
export interface VerifyCommandOptions {
|
|
20
|
-
ctx:
|
|
26
|
+
ctx: MiokuContext;
|
|
21
27
|
getVerifyConfig: () => VerifyConfig;
|
|
22
28
|
setVerifyConfig: (next: VerifyConfig) => Promise<void>;
|
|
23
29
|
verifyController: VerifyController;
|
|
@@ -29,352 +35,363 @@ const VERIFY_MODE_LABELS: Record<string, string> = {
|
|
|
29
35
|
chiral: "手性碳",
|
|
30
36
|
};
|
|
31
37
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
type VerifyContext = CommandExecutionContext & {
|
|
39
|
+
bot: Bot;
|
|
40
|
+
groupIdNum: number;
|
|
41
|
+
groupName: string;
|
|
42
|
+
selfId: number;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
async function extractQuoteImageUrls(event: MessageEvent): Promise<string[]> {
|
|
46
|
+
const eventAny = event as MessageEvent & {
|
|
47
|
+
getQuoteMsg?: () => Promise<{ message?: unknown[] } | null>;
|
|
48
|
+
};
|
|
49
|
+
if (typeof eventAny.getQuoteMsg !== "function") return [];
|
|
50
|
+
const quoteMsg = await eventAny.getQuoteMsg().catch(() => null);
|
|
35
51
|
if (!quoteMsg || !Array.isArray(quoteMsg.message)) return [];
|
|
36
|
-
return extractImageUrls(quoteMsg.message);
|
|
52
|
+
return extractImageUrls(quoteMsg.message as Parameters<typeof extractImageUrls>[0]);
|
|
37
53
|
}
|
|
38
54
|
|
|
39
55
|
export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
40
56
|
const { ctx, getVerifyConfig, setVerifyConfig, verifyController } = options;
|
|
41
57
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const bot = ctx.pickBot(selfId);
|
|
68
|
-
if (!bot) return;
|
|
69
|
-
|
|
70
|
-
const isMaster = ctx.isOwner?.(event) ?? false;
|
|
71
|
-
const senderRole = await getMemberRole(bot, groupId, event.user_id);
|
|
72
|
-
const hasAdminPermission =
|
|
73
|
-
isMaster || senderRole === "owner" || senderRole === "admin";
|
|
74
|
-
|
|
75
|
-
const ensureAdminPermission = async (instruction?: string) => {
|
|
76
|
-
if (hasAdminPermission) return true;
|
|
77
|
-
await replyAdminErrorNotice({
|
|
78
|
-
ctx,
|
|
79
|
-
event,
|
|
80
|
-
instruction:
|
|
81
|
-
instruction ||
|
|
82
|
-
"用户想使用入群验证相关指令,但不是群主或管理员,无权限。请告诉用户需要管理权限。",
|
|
83
|
-
fallbackMessage: "你得是群主或管理员才行哦~",
|
|
84
|
-
});
|
|
85
|
-
return false;
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
const groupName =
|
|
89
|
-
String(event?.group?.group_name || "").trim() || String(groupId);
|
|
90
|
-
|
|
91
|
-
// /开启验证 | #开启验证
|
|
92
|
-
if (text === "/开启验证" || text === "#开启验证") {
|
|
93
|
-
if (!(await ensureAdminPermission())) return;
|
|
94
|
-
|
|
95
|
-
const botRole = await getMemberRole(bot, groupId, selfId);
|
|
96
|
-
if (botRole !== "owner" && botRole !== "admin") {
|
|
58
|
+
const register = (
|
|
59
|
+
def: Omit<CommandDefinition, "handler">,
|
|
60
|
+
run: (c: VerifyContext) => Promise<void>,
|
|
61
|
+
) => {
|
|
62
|
+
ctx.command({
|
|
63
|
+
...def,
|
|
64
|
+
prefixes: false,
|
|
65
|
+
handler: async (c) => {
|
|
66
|
+
const event = c.event;
|
|
67
|
+
if (event.user_id === event.self_id) return;
|
|
68
|
+
if (event.message_type !== "group") return;
|
|
69
|
+
const bot = event.bot;
|
|
70
|
+
if (!bot) return;
|
|
71
|
+
const groupIdNum = event.group_id ? Number(event.group_id) : 0;
|
|
72
|
+
if (!groupIdNum) return;
|
|
73
|
+
try {
|
|
74
|
+
await run({
|
|
75
|
+
...c,
|
|
76
|
+
bot,
|
|
77
|
+
groupIdNum,
|
|
78
|
+
groupName: String(event?.group?.group_name || "").trim() || String(groupIdNum),
|
|
79
|
+
selfId: Number(event.self_id),
|
|
80
|
+
});
|
|
81
|
+
} catch (err) {
|
|
82
|
+
ctx.logger.error(`[admin verify] 未捕获异常: ${String(err)}`);
|
|
97
83
|
await replyAdminErrorNotice({
|
|
98
84
|
ctx,
|
|
99
85
|
event,
|
|
100
|
-
instruction:
|
|
101
|
-
|
|
102
|
-
|
|
86
|
+
instruction: `入群验证指令执行时发生未捕获异常:${String(err)},请简要说明失败并建议稍后重试。`,
|
|
87
|
+
fallbackMessage: `出错了,笨蛋~ ${String(err)}`,
|
|
88
|
+
error: err,
|
|
103
89
|
});
|
|
104
|
-
return;
|
|
105
90
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
register(
|
|
96
|
+
{
|
|
97
|
+
name: "/开启验证",
|
|
98
|
+
match: /^[/#]开启验证$/,
|
|
99
|
+
permission: "admin",
|
|
100
|
+
description: "开启本群入群验证",
|
|
101
|
+
},
|
|
102
|
+
async (c) => {
|
|
103
|
+
const { ctx, event, bot, groupIdNum, selfId } = c;
|
|
104
|
+
const botRole = await getMemberRole(bot, groupIdNum, selfId);
|
|
105
|
+
if (botRole !== "owner" && botRole !== "admin") {
|
|
106
|
+
await replyAdminErrorNotice({
|
|
107
|
+
ctx,
|
|
108
|
+
event,
|
|
109
|
+
instruction:
|
|
110
|
+
"用户想开启入群验证,但Bot在群内不是群主或管理员,无法执行撤回/踢人等验证操作。请告诉用户需要先把Bot设为群主或管理员。",
|
|
111
|
+
fallbackMessage: "我得是群主或管理员才能开验证哦~",
|
|
115
112
|
});
|
|
116
|
-
await setVerifyConfig(next);
|
|
117
|
-
await event.reply("已开启入群验证~", true);
|
|
118
113
|
return;
|
|
119
114
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if (
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
115
|
+
const current = getVerifyConfig();
|
|
116
|
+
const groupCfg = getGroupVerifyConfig(current, groupIdNum);
|
|
117
|
+
if (groupCfg.enabled) {
|
|
118
|
+
await event.reply("本群已经开启验证啦~", true);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const next = upsertGroupVerifyConfig(current, groupIdNum, {
|
|
122
|
+
enabled: true,
|
|
123
|
+
});
|
|
124
|
+
await setVerifyConfig(next);
|
|
125
|
+
await event.reply("已开启入群验证~", true);
|
|
126
|
+
},
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
register(
|
|
130
|
+
{
|
|
131
|
+
name: "/关闭验证",
|
|
132
|
+
match: /^[/#]关闭验证$/,
|
|
133
|
+
permission: "admin",
|
|
134
|
+
description: "关闭本群入群验证",
|
|
135
|
+
},
|
|
136
|
+
async (c) => {
|
|
137
|
+
const { event, groupIdNum } = c;
|
|
138
|
+
const current = getVerifyConfig();
|
|
139
|
+
const groupCfg = getGroupVerifyConfig(current, groupIdNum);
|
|
140
|
+
if (!groupCfg.enabled) {
|
|
141
|
+
await event.reply("本群还没开启验证哦~", true);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const next = upsertGroupVerifyConfig(current, groupIdNum, {
|
|
145
|
+
enabled: false,
|
|
146
|
+
});
|
|
147
|
+
await setVerifyConfig(next);
|
|
148
|
+
await event.reply("已关闭入群验证~", true);
|
|
149
|
+
},
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
register(
|
|
153
|
+
{
|
|
154
|
+
name: "/切换验证模式",
|
|
155
|
+
match: /^[/#]切换验证模式(?:\s|$)/,
|
|
156
|
+
permission: "admin",
|
|
157
|
+
description: "切换验证模式:回应/数字/手性碳",
|
|
158
|
+
usage: "/切换验证模式 回应",
|
|
159
|
+
},
|
|
160
|
+
async (c) => {
|
|
161
|
+
const { ctx, event, groupIdNum, body } = c;
|
|
162
|
+
const arg = body.replace(/^[/#]切换验证模式\s*/, "").trim();
|
|
163
|
+
const mode = normalizeVerifyMode(arg);
|
|
164
|
+
if (!arg) {
|
|
165
|
+
await replyAdminErrorNotice({
|
|
166
|
+
ctx,
|
|
167
|
+
event,
|
|
168
|
+
instruction:
|
|
169
|
+
"用户想切换验证模式但没指定模式。请告诉用户可用模式:回应、数字、手性碳,用法:/切换验证模式 回应。",
|
|
170
|
+
fallbackMessage: "想切换成哪种模式呀~回应/数字/手性碳",
|
|
171
|
+
});
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const current = getVerifyConfig();
|
|
175
|
+
const next = upsertGroupVerifyConfig(current, groupIdNum, { mode });
|
|
176
|
+
await setVerifyConfig(next);
|
|
177
|
+
await event.reply(
|
|
178
|
+
`验证模式已切换为:${VERIFY_MODE_LABELS[mode]}~`,
|
|
179
|
+
true,
|
|
180
|
+
);
|
|
181
|
+
},
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
register(
|
|
185
|
+
{
|
|
186
|
+
name: "/绕过验证",
|
|
187
|
+
match: /^[/#]绕过验证(?:\s|$)/,
|
|
188
|
+
permission: "admin",
|
|
189
|
+
description: "绕过指定新成员的验证直接欢迎",
|
|
190
|
+
usage: "/绕过验证 @新成员",
|
|
191
|
+
},
|
|
192
|
+
async (c) => {
|
|
193
|
+
const { ctx, event, groupIdNum, groupName, selfId } = c;
|
|
194
|
+
const atUser = getAtUserId(event.message);
|
|
195
|
+
if (!atUser) {
|
|
196
|
+
await replyAdminErrorNotice({
|
|
197
|
+
ctx,
|
|
198
|
+
event,
|
|
199
|
+
instruction:
|
|
200
|
+
"用户想绕过某位新成员的验证,但没有@目标成员。请提醒用户在命令后@要绕过验证的新成员。",
|
|
201
|
+
fallbackMessage: "要绕过谁呀~先@一下~",
|
|
202
|
+
});
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
try {
|
|
206
|
+
await verifyController.bypassVerification({
|
|
207
|
+
selfId,
|
|
208
|
+
groupId: groupIdNum,
|
|
209
|
+
userId: atUser,
|
|
210
|
+
groupName,
|
|
211
|
+
});
|
|
212
|
+
await event.reply("done");
|
|
213
|
+
} catch (err) {
|
|
214
|
+
await replyAdminErrorNotice({
|
|
215
|
+
ctx,
|
|
216
|
+
event,
|
|
217
|
+
instruction: `绕过验证执行失败:${String(err)},请简要说明失败并建议稍后重试。`,
|
|
218
|
+
fallbackMessage: `出错了,笨蛋~ ${String(err)}`,
|
|
219
|
+
error: err,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
register(
|
|
226
|
+
{
|
|
227
|
+
name: "/重新验证",
|
|
228
|
+
match: /^[/#]重新验证(?:\s|$)/,
|
|
229
|
+
permission: "admin",
|
|
230
|
+
description: "让指定成员重新进行入群验证",
|
|
231
|
+
usage: "/重新验证 @成员",
|
|
232
|
+
},
|
|
233
|
+
async (c) => {
|
|
234
|
+
const { ctx, event, bot, groupIdNum, groupName, selfId } = c;
|
|
235
|
+
const atUser = getAtUserId(event.message);
|
|
236
|
+
if (!atUser) {
|
|
237
|
+
await replyAdminErrorNotice({
|
|
238
|
+
ctx,
|
|
239
|
+
event,
|
|
240
|
+
instruction:
|
|
241
|
+
"用户想让某人重新进行入群验证,但没有@目标成员。请提醒用户在命令后@要重新验证的成员。",
|
|
242
|
+
fallbackMessage: "要重新验证谁呀~先@一下~",
|
|
243
|
+
});
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
const isTargetMaster = ctx.isMaster?.(atUser) ?? false;
|
|
247
|
+
const targetRole = await getMemberRole(bot, groupIdNum, atUser);
|
|
248
|
+
if (isTargetMaster || targetRole === "owner" || targetRole === "admin") {
|
|
249
|
+
await replyAdminErrorNotice({
|
|
250
|
+
ctx,
|
|
251
|
+
event,
|
|
252
|
+
instruction:
|
|
253
|
+
"用户想让一位群主/管理员/主人重新验证,但这些成员无需验证。请告诉用户该成员是管理/群主或主人,不能对其重新验证。",
|
|
254
|
+
fallbackMessage: "管理/群主或主人可不用验证哦~",
|
|
255
|
+
});
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
try {
|
|
259
|
+
const started = await verifyController.restartVerification(
|
|
260
|
+
{
|
|
261
|
+
selfId,
|
|
262
|
+
groupId: groupIdNum,
|
|
263
|
+
userId: atUser,
|
|
264
|
+
groupName,
|
|
265
|
+
},
|
|
266
|
+
bot,
|
|
267
|
+
);
|
|
268
|
+
if (!started) {
|
|
128
269
|
await event.reply("本群还没开启验证哦~", true);
|
|
129
|
-
return;
|
|
130
270
|
}
|
|
131
|
-
|
|
132
|
-
|
|
271
|
+
} catch (err) {
|
|
272
|
+
await replyAdminErrorNotice({
|
|
273
|
+
ctx,
|
|
274
|
+
event,
|
|
275
|
+
instruction: `重新验证执行失败:${String(err)},请简要说明失败并建议稍后重试。`,
|
|
276
|
+
fallbackMessage: `出错了,笨蛋~ ${String(err)}`,
|
|
277
|
+
error: err,
|
|
133
278
|
});
|
|
134
|
-
await setVerifyConfig(next);
|
|
135
|
-
await event.reply("已关闭入群验证~", true);
|
|
136
|
-
return;
|
|
137
279
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
280
|
+
},
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
register(
|
|
284
|
+
{
|
|
285
|
+
name: "/入群提示",
|
|
286
|
+
match: /^[/#]入群提示(?:\s|$)/,
|
|
287
|
+
permission: "admin",
|
|
288
|
+
description: "设置本群自定义入群提示,可附带文字+图片",
|
|
289
|
+
usage: "/入群提示 xxx;/入群提示 关闭",
|
|
290
|
+
},
|
|
291
|
+
async (c) => {
|
|
292
|
+
const { ctx, event, groupIdNum, body } = c;
|
|
293
|
+
const rawArg = body.replace(/^[/#]入群提示\s*/, "").trim();
|
|
294
|
+
const current = getVerifyConfig();
|
|
295
|
+
const groupCfg = getGroupVerifyConfig(current, groupIdNum);
|
|
296
|
+
const directImageUrls = extractImageUrls(event.message);
|
|
297
|
+
const quoteImageUrls = await extractQuoteImageUrls(event).catch(() => []);
|
|
298
|
+
const imageUrls =
|
|
299
|
+
directImageUrls.length > 0 ? directImageUrls : quoteImageUrls;
|
|
300
|
+
|
|
301
|
+
if (rawArg === "关闭" || rawArg === "清空" || rawArg === "关") {
|
|
302
|
+
if (!hasCustomPrompt(groupCfg)) {
|
|
303
|
+
await event.reply("本群还没设置自定义入群提示哦~", true);
|
|
158
304
|
return;
|
|
159
305
|
}
|
|
160
|
-
|
|
161
|
-
const
|
|
162
|
-
|
|
306
|
+
const removedFile = groupCfg.promptImage;
|
|
307
|
+
const next = upsertGroupVerifyConfig(current, groupIdNum, {
|
|
308
|
+
customPrompt: "",
|
|
309
|
+
promptImage: "",
|
|
310
|
+
});
|
|
163
311
|
await setVerifyConfig(next);
|
|
164
|
-
await
|
|
165
|
-
|
|
166
|
-
|
|
312
|
+
await pruneGroupPromptImages(groupIdNum, []).catch(() => {});
|
|
313
|
+
ctx.logger.info(
|
|
314
|
+
`admin verify 关闭群 ${groupIdNum} 自定义入群提示,清理图片 ${removedFile}`,
|
|
167
315
|
);
|
|
316
|
+
await event.reply("已关闭本群自定义入群提示~", true);
|
|
168
317
|
return;
|
|
169
318
|
}
|
|
170
319
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
await replyAdminErrorNotice({
|
|
178
|
-
ctx,
|
|
179
|
-
event,
|
|
180
|
-
instruction:
|
|
181
|
-
"用户想绕过某位新成员的验证,但没有@目标成员。请提醒用户在命令后@要绕过验证的新成员。",
|
|
182
|
-
fallbackMessage: "要绕过谁呀~先@一下~",
|
|
183
|
-
});
|
|
320
|
+
if (!rawArg && !imageUrls.length) {
|
|
321
|
+
if (!hasCustomPrompt(groupCfg)) {
|
|
322
|
+
await event.reply(
|
|
323
|
+
"用法:/入群提示 xxx(最多 50 字),可附带图片(当前消息或引用消息中的图片)一起发送;/入群提示 关闭 关闭自定义提示~",
|
|
324
|
+
true,
|
|
325
|
+
);
|
|
184
326
|
return;
|
|
185
327
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
event,
|
|
199
|
-
instruction: `绕过验证执行失败:${String(err)},请简要说明失败并建议稍后重试。`,
|
|
200
|
-
fallbackMessage: `出错了,笨蛋~ ${String(err)}`,
|
|
201
|
-
error: err,
|
|
202
|
-
});
|
|
203
|
-
}
|
|
328
|
+
const lines = ["已开启本群自定义入群提示"];
|
|
329
|
+
lines.push(
|
|
330
|
+
groupCfg.customPrompt
|
|
331
|
+
? `文字:${groupCfg.customPrompt}`
|
|
332
|
+
: "文字:(未设置)",
|
|
333
|
+
);
|
|
334
|
+
lines.push(
|
|
335
|
+
groupCfg.promptImage
|
|
336
|
+
? `图片:已设置(filename=${groupCfg.promptImage})`
|
|
337
|
+
: "图片:(未设置)",
|
|
338
|
+
);
|
|
339
|
+
await event.reply(lines.join("\n"), true);
|
|
204
340
|
return;
|
|
205
341
|
}
|
|
206
342
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
if (
|
|
210
|
-
|
|
211
|
-
const atUser = getAtUserId(event.message);
|
|
212
|
-
if (!atUser) {
|
|
213
|
-
await replyAdminErrorNotice({
|
|
214
|
-
ctx,
|
|
215
|
-
event,
|
|
216
|
-
instruction:
|
|
217
|
-
"用户想让某人重新进行入群验证,但没有@目标成员。请提醒用户在命令后@要重新验证的成员。",
|
|
218
|
-
fallbackMessage: "要重新验证谁呀~先@一下~",
|
|
219
|
-
});
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
const isTargetMaster = ctx.isOwner?.(atUser) ?? false;
|
|
224
|
-
const targetRole = await getMemberRole(bot, groupId, atUser);
|
|
225
|
-
if (isTargetMaster || targetRole === "owner" || targetRole === "admin") {
|
|
343
|
+
if (rawArg) {
|
|
344
|
+
const argLength = Array.from(rawArg).length;
|
|
345
|
+
if (argLength > MAX_CUSTOM_PROMPT_LENGTH) {
|
|
226
346
|
await replyAdminErrorNotice({
|
|
227
347
|
ctx,
|
|
228
348
|
event,
|
|
229
|
-
instruction:
|
|
230
|
-
|
|
231
|
-
fallbackMessage: "管理/群主或主人可不用验证哦~",
|
|
349
|
+
instruction: `用户想设置本群入群提示,但内容长度 ${argLength} 超过了上限 ${MAX_CUSTOM_PROMPT_LENGTH} 字,请明确告诉用户最多 ${MAX_CUSTOM_PROMPT_LENGTH} 字。`,
|
|
350
|
+
fallbackMessage: `最多 ${MAX_CUSTOM_PROMPT_LENGTH} 字哦~当前 ${argLength} 字`,
|
|
232
351
|
});
|
|
233
352
|
return;
|
|
234
353
|
}
|
|
235
|
-
|
|
236
|
-
try {
|
|
237
|
-
const started = await verifyController.restartVerification({
|
|
238
|
-
selfId,
|
|
239
|
-
groupId,
|
|
240
|
-
userId: atUser,
|
|
241
|
-
groupName,
|
|
242
|
-
});
|
|
243
|
-
if (!started) {
|
|
244
|
-
await event.reply("本群还没开启验证哦~", true);
|
|
245
|
-
}
|
|
246
|
-
} catch (err) {
|
|
247
|
-
await replyAdminErrorNotice({
|
|
248
|
-
ctx,
|
|
249
|
-
event,
|
|
250
|
-
instruction: `重新验证执行失败:${String(err)},请简要说明失败并建议稍后重试。`,
|
|
251
|
-
fallbackMessage: `出错了,笨蛋~ ${String(err)}`,
|
|
252
|
-
error: err,
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
return;
|
|
256
354
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
const
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
return;
|
|
276
|
-
}
|
|
277
|
-
const removedFile = groupCfg.promptImage;
|
|
278
|
-
const next = upsertGroupVerifyConfig(current, groupId, {
|
|
279
|
-
customPrompt: "",
|
|
280
|
-
promptImage: "",
|
|
281
|
-
});
|
|
282
|
-
await setVerifyConfig(next);
|
|
283
|
-
await pruneGroupPromptImages(groupId, []).catch(() => {});
|
|
284
|
-
ctx.logger.info(
|
|
285
|
-
`admin verify 关闭群 ${groupId} 自定义入群提示,清理图片 ${removedFile}`,
|
|
286
|
-
);
|
|
287
|
-
await event.reply("已关闭本群自定义入群提示~", true);
|
|
288
|
-
return;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
if (!rawArg && !imageUrls.length) {
|
|
292
|
-
if (!hasCustomPrompt(groupCfg)) {
|
|
293
|
-
await event.reply(
|
|
294
|
-
"用法:/入群提示 xxx(最多 50 字),可附带图片(当前消息或引用消息中的图片)一起发送;/入群提示 关闭 关闭自定义提示~",
|
|
295
|
-
true,
|
|
355
|
+
const nextPrompt = rawArg
|
|
356
|
+
? normalizeCustomPrompt(rawArg)
|
|
357
|
+
: groupCfg.customPrompt;
|
|
358
|
+
|
|
359
|
+
let nextImage = groupCfg.promptImage;
|
|
360
|
+
let imageNote = "";
|
|
361
|
+
if (imageUrls.length) {
|
|
362
|
+
const targetUrl = imageUrls[0];
|
|
363
|
+
const savedImage = await saveRemoteImageAsPrompt(groupIdNum, targetUrl);
|
|
364
|
+
if (savedImage) {
|
|
365
|
+
const previousImage = groupCfg.promptImage;
|
|
366
|
+
nextImage = savedImage.filename;
|
|
367
|
+
imageNote = previousImage
|
|
368
|
+
? `图片已替换(旧文件 ${previousImage} 已删除)`
|
|
369
|
+
: `图片已设置(${savedImage.filename})`;
|
|
370
|
+
if (previousImage) {
|
|
371
|
+
ctx.logger.info(
|
|
372
|
+
`admin verify 替换群 ${groupIdNum} 入群提示图片:${previousImage} -> ${savedImage.filename}`,
|
|
296
373
|
);
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
299
|
-
const lines = ["已开启本群自定义入群提示"];
|
|
300
|
-
lines.push(
|
|
301
|
-
groupCfg.customPrompt
|
|
302
|
-
? `文字:${groupCfg.customPrompt}`
|
|
303
|
-
: "文字:(未设置)",
|
|
304
|
-
);
|
|
305
|
-
lines.push(
|
|
306
|
-
groupCfg.promptImage
|
|
307
|
-
? `图片:已设置(filename=${groupCfg.promptImage})`
|
|
308
|
-
: "图片:(未设置)",
|
|
309
|
-
);
|
|
310
|
-
await event.reply(lines.join("\n"), true);
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
if (rawArg) {
|
|
315
|
-
const argLength = Array.from(rawArg).length;
|
|
316
|
-
if (argLength > MAX_CUSTOM_PROMPT_LENGTH) {
|
|
317
|
-
await replyAdminErrorNotice({
|
|
318
|
-
ctx,
|
|
319
|
-
event,
|
|
320
|
-
instruction: `用户想设置本群入群提示,但内容长度 ${argLength} 超过了上限 ${MAX_CUSTOM_PROMPT_LENGTH} 字,请明确告诉用户最多 ${MAX_CUSTOM_PROMPT_LENGTH} 字。`,
|
|
321
|
-
fallbackMessage: `最多 ${MAX_CUSTOM_PROMPT_LENGTH} 字哦~当前 ${argLength} 字`,
|
|
322
|
-
});
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
const nextPrompt = rawArg
|
|
327
|
-
? normalizeCustomPrompt(rawArg)
|
|
328
|
-
: groupCfg.customPrompt;
|
|
329
|
-
|
|
330
|
-
let nextImage = groupCfg.promptImage;
|
|
331
|
-
let imageNote = "";
|
|
332
|
-
if (imageUrls.length) {
|
|
333
|
-
const targetUrl = imageUrls[0];
|
|
334
|
-
const savedImage = await saveRemoteImageAsPrompt(groupId, targetUrl);
|
|
335
|
-
if (savedImage) {
|
|
336
|
-
const previousImage = groupCfg.promptImage;
|
|
337
|
-
nextImage = savedImage.filename;
|
|
338
|
-
imageNote = previousImage
|
|
339
|
-
? `图片已替换(旧文件 ${previousImage} 已删除)`
|
|
340
|
-
: `图片已设置(${savedImage.filename})`;
|
|
341
|
-
if (previousImage) {
|
|
342
|
-
ctx.logger.info(
|
|
343
|
-
`admin verify 替换群 ${groupId} 入群提示图片:${previousImage} -> ${savedImage.filename}`,
|
|
344
|
-
);
|
|
345
|
-
}
|
|
346
|
-
} else {
|
|
347
|
-
imageNote = "图片下载失败,请稍后重试";
|
|
348
374
|
}
|
|
375
|
+
} else {
|
|
376
|
+
imageNote = "图片下载失败,请稍后重试";
|
|
349
377
|
}
|
|
350
|
-
|
|
351
|
-
const next = upsertGroupVerifyConfig(current, groupId, {
|
|
352
|
-
customPrompt: nextPrompt,
|
|
353
|
-
promptImage: nextImage,
|
|
354
|
-
});
|
|
355
|
-
await setVerifyConfig(next);
|
|
356
|
-
await pruneGroupPromptImages(groupId, nextImage ? [nextImage] : []).catch(
|
|
357
|
-
() => {},
|
|
358
|
-
);
|
|
359
|
-
|
|
360
|
-
const lines = ["已更新本群自定义入群提示"];
|
|
361
|
-
if (rawArg) lines.push(`文字:${nextPrompt}`);
|
|
362
|
-
else if (groupCfg.customPrompt)
|
|
363
|
-
lines.push(`文字(保持):${groupCfg.customPrompt}`);
|
|
364
|
-
if (imageUrls.length && imageNote) lines.push(imageNote);
|
|
365
|
-
await event.reply(lines.join("\n"), true);
|
|
366
|
-
return;
|
|
367
378
|
}
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
ctx,
|
|
373
|
-
event,
|
|
374
|
-
instruction: `入群验证指令执行时发生未捕获异常:${String(err)},请简要说明失败并建议稍后重试。`,
|
|
375
|
-
fallbackMessage: `出错了,笨蛋~ ${String(err)}`,
|
|
376
|
-
error: err,
|
|
379
|
+
|
|
380
|
+
const next = upsertGroupVerifyConfig(current, groupIdNum, {
|
|
381
|
+
customPrompt: nextPrompt,
|
|
382
|
+
promptImage: nextImage,
|
|
377
383
|
});
|
|
378
|
-
|
|
379
|
-
|
|
384
|
+
await setVerifyConfig(next);
|
|
385
|
+
await pruneGroupPromptImages(groupIdNum, nextImage ? [nextImage] : []).catch(
|
|
386
|
+
() => {},
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
const lines = ["已更新本群自定义入群提示"];
|
|
390
|
+
if (rawArg) lines.push(`文字:${nextPrompt}`);
|
|
391
|
+
else if (groupCfg.customPrompt)
|
|
392
|
+
lines.push(`文字(保持):${groupCfg.customPrompt}`);
|
|
393
|
+
if (imageUrls.length && imageNote) lines.push(imageNote);
|
|
394
|
+
await event.reply(lines.join("\n"), true);
|
|
395
|
+
},
|
|
396
|
+
);
|
|
380
397
|
}
|