mioku-plugin-admin 2.3.5 → 3.0.0
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 +34 -54
- package/commands/notice.ts +3 -3
- package/commands/personal.ts +112 -184
- package/commands/verify.ts +43 -35
- package/config.ts +29 -17
- package/index.ts +5 -5
- package/notify/index.ts +108 -138
- package/notify/welcome.ts +52 -44
- package/package.json +3 -5
- 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/personal.ts
CHANGED
|
@@ -1,18 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
MessageEvent,
|
|
4
|
-
RecvAtElement,
|
|
5
|
-
RecvElement,
|
|
6
|
-
RecvFaceElement,
|
|
7
|
-
RecvFileElement,
|
|
8
|
-
RecvForwardElement,
|
|
9
|
-
RecvImageElement,
|
|
10
|
-
RecvJsonElement,
|
|
11
|
-
RecvRecordElement,
|
|
12
|
-
RecvReplyElement,
|
|
13
|
-
RecvTextElement,
|
|
14
|
-
RecvVideoElement,
|
|
15
|
-
} from "napcat-sdk";
|
|
1
|
+
import type { Bot, MessageEvent, MessageInput, MessageTarget, MiokuContext, MessageSegment } from "mioku";
|
|
2
|
+
import {createGroupRef} from "mioku";
|
|
16
3
|
import { extractImageUrl } from "../config";
|
|
17
4
|
import { replyAdminErrorNotice } from "./notice";
|
|
18
5
|
|
|
@@ -23,80 +10,70 @@ function parseProfileSex(value: string): 0 | 1 | 2 {
|
|
|
23
10
|
return 0;
|
|
24
11
|
}
|
|
25
12
|
|
|
26
|
-
function toSendSegment(ctx:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if (seg.type === "image" || seg.type === "record" || seg.type === "video") {
|
|
33
|
-
const mediaSeg = seg as
|
|
34
|
-
| RecvImageElement
|
|
35
|
-
| RecvRecordElement
|
|
36
|
-
| RecvVideoElement;
|
|
37
|
-
const source = String(mediaSeg.url || mediaSeg.file || "").trim();
|
|
38
|
-
if (!source) return null;
|
|
39
|
-
if (seg.type === "image") {
|
|
40
|
-
return ctx.segment.image(source);
|
|
13
|
+
function toSendSegment(ctx: MiokuContext, seg: MessageSegment): MessageSegment | null {
|
|
14
|
+
const data = seg.data as Record<string, unknown>;
|
|
15
|
+
switch (seg.type) {
|
|
16
|
+
case "text": {
|
|
17
|
+
const text = String(data.text ?? "").trim();
|
|
18
|
+
return text ? ctx.segment.text(text) : null;
|
|
41
19
|
}
|
|
42
|
-
|
|
43
|
-
|
|
20
|
+
case "image": {
|
|
21
|
+
const source = String(data.url ?? data.file ?? "").trim();
|
|
22
|
+
return source ? ctx.segment.image(source) : null;
|
|
44
23
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const data = (seg as RecvJsonElement).data;
|
|
79
|
-
return ctx.segment.json ? ctx.segment.json(data) : null;
|
|
24
|
+
case "record": {
|
|
25
|
+
const source = String(data.file ?? data.url ?? "").trim();
|
|
26
|
+
return source ? ctx.segment.raw("record", { file: source }) : null;
|
|
27
|
+
}
|
|
28
|
+
case "video": {
|
|
29
|
+
const source = String(data.file ?? data.url ?? "").trim();
|
|
30
|
+
return source ? ctx.segment.raw("video", { file: source }) : null;
|
|
31
|
+
}
|
|
32
|
+
case "file": {
|
|
33
|
+
const source = String(data.file ?? data.url ?? "").trim();
|
|
34
|
+
return source ? ctx.segment.raw("file", { file: source }) : null;
|
|
35
|
+
}
|
|
36
|
+
case "at": {
|
|
37
|
+
const target = String(data.qq ?? data.target ?? "");
|
|
38
|
+
return target && target !== "all" ? ctx.segment.at(target) : null;
|
|
39
|
+
}
|
|
40
|
+
case "face": {
|
|
41
|
+
const id = data.id;
|
|
42
|
+
return id == null ? null : ctx.segment.raw("face", { id: String(id) });
|
|
43
|
+
}
|
|
44
|
+
case "reply": {
|
|
45
|
+
const id = data.message_id ?? data.id;
|
|
46
|
+
return id == null ? null : ctx.segment.reply(String(id));
|
|
47
|
+
}
|
|
48
|
+
case "forward": {
|
|
49
|
+
const id = data.id;
|
|
50
|
+
return id == null ? null : ctx.segment.raw("forward", { id: String(id) });
|
|
51
|
+
}
|
|
52
|
+
case "json": {
|
|
53
|
+
return ctx.segment.raw("json", data);
|
|
54
|
+
}
|
|
55
|
+
default:
|
|
56
|
+
return seg;
|
|
80
57
|
}
|
|
81
|
-
|
|
82
|
-
return null;
|
|
83
58
|
}
|
|
84
59
|
|
|
85
60
|
function normalizeIncomingSegments(
|
|
86
|
-
ctx:
|
|
87
|
-
segments:
|
|
88
|
-
):
|
|
61
|
+
ctx: MiokuContext,
|
|
62
|
+
segments: readonly MessageSegment[],
|
|
63
|
+
): MessageSegment[] {
|
|
89
64
|
if (!Array.isArray(segments)) return [];
|
|
90
|
-
return segments
|
|
65
|
+
return segments
|
|
66
|
+
.map((seg) => toSendSegment(ctx, seg))
|
|
67
|
+
.filter((seg): seg is MessageSegment => seg !== null);
|
|
91
68
|
}
|
|
92
69
|
|
|
93
70
|
function buildForwardPayloadAfterCommand(
|
|
94
|
-
ctx:
|
|
95
|
-
message:
|
|
71
|
+
ctx: MiokuContext,
|
|
72
|
+
message: readonly MessageSegment[],
|
|
96
73
|
commandPattern: RegExp,
|
|
97
74
|
fallbackText?: string,
|
|
98
|
-
):
|
|
99
|
-
const payload:
|
|
75
|
+
): MessageSegment[] {
|
|
76
|
+
const payload: MessageSegment[] = [];
|
|
100
77
|
let stripped = false;
|
|
101
78
|
|
|
102
79
|
for (const seg of message) {
|
|
@@ -107,7 +84,7 @@ function buildForwardPayloadAfterCommand(
|
|
|
107
84
|
}
|
|
108
85
|
continue;
|
|
109
86
|
}
|
|
110
|
-
const original = String((seg as
|
|
87
|
+
const original = String((seg.data as Record<string, unknown>).text ?? "");
|
|
111
88
|
if (!stripped) {
|
|
112
89
|
const nextText = original.replace(commandPattern, "");
|
|
113
90
|
if (nextText !== original) {
|
|
@@ -134,87 +111,46 @@ function buildForwardPayloadAfterCommand(
|
|
|
134
111
|
return payload;
|
|
135
112
|
}
|
|
136
113
|
|
|
137
|
-
function toForwardMessages(bot: any, nodes: any[]): any[] {
|
|
138
|
-
const normalizeElements = (elements: any[]): any[] => {
|
|
139
|
-
if (typeof bot?.normalizeSendable === "function") {
|
|
140
|
-
return bot.normalizeSendable(elements);
|
|
141
|
-
}
|
|
142
|
-
return elements.map((element: any) => {
|
|
143
|
-
if (
|
|
144
|
-
element &&
|
|
145
|
-
typeof element === "object" &&
|
|
146
|
-
"type" in element &&
|
|
147
|
-
"data" in element
|
|
148
|
-
) {
|
|
149
|
-
return element;
|
|
150
|
-
}
|
|
151
|
-
if (element && typeof element === "object" && "type" in element) {
|
|
152
|
-
const { type, ...data } = element;
|
|
153
|
-
return { type, data };
|
|
154
|
-
}
|
|
155
|
-
return element;
|
|
156
|
-
});
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
return nodes.map((node: any) => {
|
|
160
|
-
const rawNode =
|
|
161
|
-
node && typeof node === "object" && "type" in node && "data" in node
|
|
162
|
-
? { type: node.type, ...node.data }
|
|
163
|
-
: node;
|
|
164
|
-
if (!rawNode || rawNode.type !== "node") {
|
|
165
|
-
return normalizeElements([rawNode])[0];
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const content = Array.isArray(rawNode.content) ? rawNode.content : [];
|
|
169
|
-
if ("id" in rawNode && rawNode.id) {
|
|
170
|
-
return {
|
|
171
|
-
type: "node",
|
|
172
|
-
data: {
|
|
173
|
-
user_id: rawNode.user_id,
|
|
174
|
-
nickname: rawNode.nickname,
|
|
175
|
-
id: rawNode.id,
|
|
176
|
-
},
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
return {
|
|
181
|
-
type: "node",
|
|
182
|
-
data: {
|
|
183
|
-
user_id: rawNode.user_id,
|
|
184
|
-
nickname: rawNode.nickname,
|
|
185
|
-
content: normalizeElements(content),
|
|
186
|
-
},
|
|
187
|
-
};
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
|
|
191
114
|
async function sendForwardByEvent(options: {
|
|
192
|
-
bot:
|
|
193
|
-
event:
|
|
194
|
-
messages:
|
|
115
|
+
bot: Bot;
|
|
116
|
+
event: MessageEvent;
|
|
117
|
+
messages: readonly unknown[];
|
|
195
118
|
}): Promise<void> {
|
|
196
119
|
const { bot, event, messages } = options;
|
|
197
120
|
const chunkSize = 50;
|
|
198
121
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
122
|
+
const nodes = (messages as Array<{
|
|
123
|
+
type?: string;
|
|
124
|
+
data?: { user_id?: string; nickname?: string; content?: unknown };
|
|
125
|
+
}>)
|
|
126
|
+
.map((node) => ({
|
|
127
|
+
user_id: String(node?.data?.user_id ?? event.user_id ?? ""),
|
|
128
|
+
nickname:
|
|
129
|
+
String(node?.data?.nickname || "") ||
|
|
130
|
+
String(node?.data?.user_id ?? event.user_id ?? "转发"),
|
|
131
|
+
content: Array.isArray(node?.data?.content)
|
|
132
|
+
? node.data.content
|
|
133
|
+
: [node?.data?.content],
|
|
134
|
+
}))
|
|
135
|
+
.filter((node) => node.content.length > 0)
|
|
136
|
+
.map((node) => ({
|
|
137
|
+
user_id: node.user_id,
|
|
138
|
+
nickname: node.nickname,
|
|
139
|
+
content: node.content as MessageInput,
|
|
140
|
+
}));
|
|
141
|
+
|
|
142
|
+
const target: MessageTarget =
|
|
143
|
+
event.message_type === "group" && event.group_id
|
|
144
|
+
? { type: "group", group_id: event.group_id }
|
|
145
|
+
: { type: "private", user_id: event.user_id ?? "" };
|
|
146
|
+
|
|
147
|
+
for (let i = 0; i < nodes.length; i += chunkSize) {
|
|
148
|
+
await bot.sendForward(target, nodes.slice(i, i + chunkSize));
|
|
213
149
|
}
|
|
214
150
|
}
|
|
215
151
|
|
|
216
|
-
export function registerPersonalCommands(ctx:
|
|
217
|
-
ctx.handle("message", async (event
|
|
152
|
+
export function registerPersonalCommands(ctx: MiokuContext) {
|
|
153
|
+
ctx.handle("message", async (event) => {
|
|
218
154
|
const text = ctx.text(event)?.trim();
|
|
219
155
|
if (!text) return;
|
|
220
156
|
if (event.user_id === event.self_id) return;
|
|
@@ -222,7 +158,7 @@ export function registerPersonalCommands(ctx: MiokiContext) {
|
|
|
222
158
|
const isMaster = ctx.isOwner?.(event) ?? false;
|
|
223
159
|
|
|
224
160
|
const selfId = event.self_id;
|
|
225
|
-
const bot =
|
|
161
|
+
const bot = event.bot;
|
|
226
162
|
if (!bot) return;
|
|
227
163
|
|
|
228
164
|
const isGroup = event.message_type === "group";
|
|
@@ -234,10 +170,11 @@ export function registerPersonalCommands(ctx: MiokiContext) {
|
|
|
234
170
|
}
|
|
235
171
|
const imageUrl = extractImageUrl(event.message);
|
|
236
172
|
if (!imageUrl) {
|
|
237
|
-
|
|
173
|
+
await event.reply("图片呢图片呢~", true);
|
|
174
|
+
return;
|
|
238
175
|
}
|
|
239
176
|
try {
|
|
240
|
-
await bot.
|
|
177
|
+
await bot.setAvatar(imageUrl);
|
|
241
178
|
await event.reply("done");
|
|
242
179
|
} catch (err) {
|
|
243
180
|
await replyAdminErrorNotice({
|
|
@@ -259,10 +196,11 @@ export function registerPersonalCommands(ctx: MiokiContext) {
|
|
|
259
196
|
}
|
|
260
197
|
const nickname = text.replace(/^\/改昵称\s*/, "").trim();
|
|
261
198
|
if (!nickname) {
|
|
262
|
-
|
|
199
|
+
await event.reply("想改成什么昵称呀~", true);
|
|
200
|
+
return;
|
|
263
201
|
}
|
|
264
202
|
try {
|
|
265
|
-
await bot.
|
|
203
|
+
await bot.setProfile({ nickname });
|
|
266
204
|
await event.reply("done");
|
|
267
205
|
} catch (err) {
|
|
268
206
|
await replyAdminErrorNotice({
|
|
@@ -283,10 +221,11 @@ export function registerPersonalCommands(ctx: MiokiContext) {
|
|
|
283
221
|
}
|
|
284
222
|
const personalNote = text.replace(/^\/改签名\s*/, "").trim();
|
|
285
223
|
if (!personalNote) {
|
|
286
|
-
|
|
224
|
+
await event.reply("想改成什么签名呀~", true);
|
|
225
|
+
return;
|
|
287
226
|
}
|
|
288
227
|
try {
|
|
289
|
-
await bot.
|
|
228
|
+
await bot.setProfile({ personal_note: personalNote });
|
|
290
229
|
await event.reply("done");
|
|
291
230
|
} catch (err) {
|
|
292
231
|
await replyAdminErrorNotice({
|
|
@@ -308,7 +247,7 @@ export function registerPersonalCommands(ctx: MiokiContext) {
|
|
|
308
247
|
const genderText = text.replace(/^\/改性别\s*/, "").trim();
|
|
309
248
|
const sex = parseProfileSex(genderText);
|
|
310
249
|
try {
|
|
311
|
-
await bot.
|
|
250
|
+
await bot.setProfile({ sex });
|
|
312
251
|
await event.reply("done");
|
|
313
252
|
} catch (err) {
|
|
314
253
|
await replyAdminErrorNotice({
|
|
@@ -338,7 +277,7 @@ export function registerPersonalCommands(ctx: MiokiContext) {
|
|
|
338
277
|
return;
|
|
339
278
|
}
|
|
340
279
|
try {
|
|
341
|
-
await bot.
|
|
280
|
+
await bot.deleteFriend(qq);
|
|
342
281
|
await event.reply("done");
|
|
343
282
|
} catch (err) {
|
|
344
283
|
await replyAdminErrorNotice({
|
|
@@ -368,10 +307,7 @@ export function registerPersonalCommands(ctx: MiokiContext) {
|
|
|
368
307
|
return;
|
|
369
308
|
}
|
|
370
309
|
try {
|
|
371
|
-
await bot.
|
|
372
|
-
group_id: targetGroup,
|
|
373
|
-
is_dismiss: false,
|
|
374
|
-
});
|
|
310
|
+
await createGroupRef(bot, String(targetGroup)).leave(false);
|
|
375
311
|
await event.reply("done");
|
|
376
312
|
} catch (err) {
|
|
377
313
|
await replyAdminErrorNotice({
|
|
@@ -420,7 +356,7 @@ export function registerPersonalCommands(ctx: MiokiContext) {
|
|
|
420
356
|
return;
|
|
421
357
|
}
|
|
422
358
|
try {
|
|
423
|
-
await bot.
|
|
359
|
+
await bot.sendMessage({ type: "private", user_id: targetUser}, payload);
|
|
424
360
|
await event.reply("done");
|
|
425
361
|
} catch (err) {
|
|
426
362
|
await replyAdminErrorNotice({
|
|
@@ -469,7 +405,7 @@ export function registerPersonalCommands(ctx: MiokiContext) {
|
|
|
469
405
|
return;
|
|
470
406
|
}
|
|
471
407
|
try {
|
|
472
|
-
await bot.
|
|
408
|
+
await bot.sendMessage({ type: "group", group_id: targetGroup}, payload);
|
|
473
409
|
await event.reply("done");
|
|
474
410
|
} catch (err) {
|
|
475
411
|
await replyAdminErrorNotice({
|
|
@@ -493,7 +429,7 @@ export function registerPersonalCommands(ctx: MiokiContext) {
|
|
|
493
429
|
return;
|
|
494
430
|
}
|
|
495
431
|
try {
|
|
496
|
-
const friendList
|
|
432
|
+
const friendList = await bot.getFriendList();
|
|
497
433
|
if (!Array.isArray(friendList) || friendList.length === 0) {
|
|
498
434
|
await replyAdminErrorNotice({
|
|
499
435
|
ctx,
|
|
@@ -503,9 +439,9 @@ export function registerPersonalCommands(ctx: MiokiContext) {
|
|
|
503
439
|
});
|
|
504
440
|
return;
|
|
505
441
|
}
|
|
506
|
-
const nodes = friendList.map((friend
|
|
507
|
-
ctx.segment.node
|
|
508
|
-
user_id:
|
|
442
|
+
const nodes = friendList.map((friend) =>
|
|
443
|
+
ctx.segment.raw("node", {
|
|
444
|
+
user_id: friend.user_id,
|
|
509
445
|
nickname:
|
|
510
446
|
friend.nickname || friend.remark || String(friend.user_id),
|
|
511
447
|
content: [
|
|
@@ -518,11 +454,7 @@ export function registerPersonalCommands(ctx: MiokiContext) {
|
|
|
518
454
|
],
|
|
519
455
|
}),
|
|
520
456
|
);
|
|
521
|
-
await sendForwardByEvent({
|
|
522
|
-
bot,
|
|
523
|
-
event,
|
|
524
|
-
messages: toForwardMessages(bot, nodes),
|
|
525
|
-
});
|
|
457
|
+
await sendForwardByEvent({ bot, event, messages: nodes });
|
|
526
458
|
} catch (err) {
|
|
527
459
|
await replyAdminErrorNotice({
|
|
528
460
|
ctx,
|
|
@@ -545,7 +477,7 @@ export function registerPersonalCommands(ctx: MiokiContext) {
|
|
|
545
477
|
return;
|
|
546
478
|
}
|
|
547
479
|
try {
|
|
548
|
-
const groupList
|
|
480
|
+
const groupList = await bot.getGroupList();
|
|
549
481
|
if (!Array.isArray(groupList) || groupList.length === 0) {
|
|
550
482
|
await replyAdminErrorNotice({
|
|
551
483
|
ctx,
|
|
@@ -555,9 +487,9 @@ export function registerPersonalCommands(ctx: MiokiContext) {
|
|
|
555
487
|
});
|
|
556
488
|
return;
|
|
557
489
|
}
|
|
558
|
-
const nodes = groupList.map((group
|
|
559
|
-
ctx.segment.node
|
|
560
|
-
user_id:
|
|
490
|
+
const nodes = groupList.map((group) =>
|
|
491
|
+
ctx.segment.raw("node", {
|
|
492
|
+
user_id: selfId,
|
|
561
493
|
nickname: String(selfId),
|
|
562
494
|
content: [
|
|
563
495
|
ctx.segment.image(
|
|
@@ -569,11 +501,7 @@ export function registerPersonalCommands(ctx: MiokiContext) {
|
|
|
569
501
|
],
|
|
570
502
|
}),
|
|
571
503
|
);
|
|
572
|
-
await sendForwardByEvent({
|
|
573
|
-
bot,
|
|
574
|
-
event,
|
|
575
|
-
messages: toForwardMessages(bot, nodes),
|
|
576
|
-
});
|
|
504
|
+
await sendForwardByEvent({ bot, event, messages: nodes });
|
|
577
505
|
} catch (err) {
|
|
578
506
|
await replyAdminErrorNotice({
|
|
579
507
|
ctx,
|
package/commands/verify.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { MiokuContext } from "mioku";
|
|
2
2
|
import { extractImageUrls, getAtUserId, getMemberRole } from "../config";
|
|
3
3
|
import {
|
|
4
4
|
getGroupVerifyConfig,
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
} from "../utils/prompt-image-store";
|
|
18
18
|
|
|
19
19
|
export interface VerifyCommandOptions {
|
|
20
|
-
ctx:
|
|
20
|
+
ctx: MiokuContext;
|
|
21
21
|
getVerifyConfig: () => VerifyConfig;
|
|
22
22
|
setVerifyConfig: (next: VerifyConfig) => Promise<void>;
|
|
23
23
|
verifyController: VerifyController;
|
|
@@ -29,24 +29,29 @@ const VERIFY_MODE_LABELS: Record<string, string> = {
|
|
|
29
29
|
chiral: "手性碳",
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
import type { MessageEvent } from "mioku";
|
|
33
|
+
|
|
34
|
+
async function extractQuoteImageUrls(event: MessageEvent): Promise<string[]> {
|
|
35
|
+
const eventAny = event as MessageEvent & {
|
|
36
|
+
getQuoteMsg?: () => Promise<{ message?: unknown[] } | null>;
|
|
37
|
+
};
|
|
38
|
+
if (typeof eventAny.getQuoteMsg !== "function") return [];
|
|
39
|
+
const quoteMsg = await eventAny.getQuoteMsg().catch(() => null);
|
|
35
40
|
if (!quoteMsg || !Array.isArray(quoteMsg.message)) return [];
|
|
36
|
-
return extractImageUrls(quoteMsg.message);
|
|
41
|
+
return extractImageUrls(quoteMsg.message as Parameters<typeof extractImageUrls>[0]);
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
40
45
|
const { ctx, getVerifyConfig, setVerifyConfig, verifyController } = options;
|
|
41
46
|
|
|
42
|
-
ctx.handle("message", async (event
|
|
47
|
+
ctx.handle("message", async (event) => {
|
|
43
48
|
const text = ctx.text(event)?.trim();
|
|
44
49
|
if (!text) return;
|
|
45
50
|
if (event.user_id === event.self_id) return;
|
|
46
51
|
|
|
47
52
|
if (event.message_type !== "group") return;
|
|
48
|
-
const
|
|
49
|
-
if (!
|
|
53
|
+
const groupIdNum = event.group_id ? Number(event.group_id) : 0;
|
|
54
|
+
if (!groupIdNum) return;
|
|
50
55
|
|
|
51
56
|
const isVerifyCommand =
|
|
52
57
|
text === "/开启验证" ||
|
|
@@ -63,12 +68,12 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
|
63
68
|
text.startsWith("#入群提示");
|
|
64
69
|
|
|
65
70
|
try {
|
|
66
|
-
const selfId = event.self_id;
|
|
67
|
-
const bot =
|
|
71
|
+
const selfId = Number(event.self_id);
|
|
72
|
+
const bot = event.bot;
|
|
68
73
|
if (!bot) return;
|
|
69
74
|
|
|
70
75
|
const isMaster = ctx.isOwner?.(event) ?? false;
|
|
71
|
-
const senderRole = await getMemberRole(bot,
|
|
76
|
+
const senderRole = await getMemberRole(bot, groupIdNum, Number(event.user_id));
|
|
72
77
|
const hasAdminPermission =
|
|
73
78
|
isMaster || senderRole === "owner" || senderRole === "admin";
|
|
74
79
|
|
|
@@ -86,13 +91,13 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
|
86
91
|
};
|
|
87
92
|
|
|
88
93
|
const groupName =
|
|
89
|
-
String(event?.group?.group_name || "").trim() || String(
|
|
94
|
+
String(event?.group?.group_name || "").trim() || String(groupIdNum);
|
|
90
95
|
|
|
91
96
|
// /开启验证 | #开启验证
|
|
92
97
|
if (text === "/开启验证" || text === "#开启验证") {
|
|
93
98
|
if (!(await ensureAdminPermission())) return;
|
|
94
99
|
|
|
95
|
-
const botRole = await getMemberRole(bot,
|
|
100
|
+
const botRole = await getMemberRole(bot, groupIdNum, selfId);
|
|
96
101
|
if (botRole !== "owner" && botRole !== "admin") {
|
|
97
102
|
await replyAdminErrorNotice({
|
|
98
103
|
ctx,
|
|
@@ -105,12 +110,12 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
|
105
110
|
}
|
|
106
111
|
|
|
107
112
|
const current = getVerifyConfig();
|
|
108
|
-
const groupCfg = getGroupVerifyConfig(current,
|
|
113
|
+
const groupCfg = getGroupVerifyConfig(current, groupIdNum);
|
|
109
114
|
if (groupCfg.enabled) {
|
|
110
115
|
await event.reply("本群已经开启验证啦~", true);
|
|
111
116
|
return;
|
|
112
117
|
}
|
|
113
|
-
const next = upsertGroupVerifyConfig(current,
|
|
118
|
+
const next = upsertGroupVerifyConfig(current, groupIdNum, {
|
|
114
119
|
enabled: true,
|
|
115
120
|
});
|
|
116
121
|
await setVerifyConfig(next);
|
|
@@ -123,12 +128,12 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
|
123
128
|
if (!(await ensureAdminPermission())) return;
|
|
124
129
|
|
|
125
130
|
const current = getVerifyConfig();
|
|
126
|
-
const groupCfg = getGroupVerifyConfig(current,
|
|
131
|
+
const groupCfg = getGroupVerifyConfig(current, groupIdNum);
|
|
127
132
|
if (!groupCfg.enabled) {
|
|
128
133
|
await event.reply("本群还没开启验证哦~", true);
|
|
129
134
|
return;
|
|
130
135
|
}
|
|
131
|
-
const next = upsertGroupVerifyConfig(current,
|
|
136
|
+
const next = upsertGroupVerifyConfig(current, groupIdNum, {
|
|
132
137
|
enabled: false,
|
|
133
138
|
});
|
|
134
139
|
await setVerifyConfig(next);
|
|
@@ -159,7 +164,7 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
|
159
164
|
}
|
|
160
165
|
|
|
161
166
|
const current = getVerifyConfig();
|
|
162
|
-
const next = upsertGroupVerifyConfig(current,
|
|
167
|
+
const next = upsertGroupVerifyConfig(current, groupIdNum, { mode });
|
|
163
168
|
await setVerifyConfig(next);
|
|
164
169
|
await event.reply(
|
|
165
170
|
`验证模式已切换为:${VERIFY_MODE_LABELS[mode]}~`,
|
|
@@ -187,7 +192,7 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
|
187
192
|
try {
|
|
188
193
|
await verifyController.bypassVerification({
|
|
189
194
|
selfId,
|
|
190
|
-
groupId,
|
|
195
|
+
groupId: groupIdNum,
|
|
191
196
|
userId: atUser,
|
|
192
197
|
groupName,
|
|
193
198
|
});
|
|
@@ -221,7 +226,7 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
|
221
226
|
}
|
|
222
227
|
|
|
223
228
|
const isTargetMaster = ctx.isOwner?.(atUser) ?? false;
|
|
224
|
-
const targetRole = await getMemberRole(bot,
|
|
229
|
+
const targetRole = await getMemberRole(bot, groupIdNum, atUser);
|
|
225
230
|
if (isTargetMaster || targetRole === "owner" || targetRole === "admin") {
|
|
226
231
|
await replyAdminErrorNotice({
|
|
227
232
|
ctx,
|
|
@@ -234,12 +239,15 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
|
234
239
|
}
|
|
235
240
|
|
|
236
241
|
try {
|
|
237
|
-
const started = await verifyController.restartVerification(
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
242
|
+
const started = await verifyController.restartVerification(
|
|
243
|
+
{
|
|
244
|
+
selfId,
|
|
245
|
+
groupId: groupIdNum,
|
|
246
|
+
userId: atUser,
|
|
247
|
+
groupName,
|
|
248
|
+
},
|
|
249
|
+
bot,
|
|
250
|
+
);
|
|
243
251
|
if (!started) {
|
|
244
252
|
await event.reply("本群还没开启验证哦~", true);
|
|
245
253
|
}
|
|
@@ -263,7 +271,7 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
|
263
271
|
|
|
264
272
|
const rawArg = text.replace(/^[/#]入群提示\s*/, "").trim();
|
|
265
273
|
const current = getVerifyConfig();
|
|
266
|
-
const groupCfg = getGroupVerifyConfig(current,
|
|
274
|
+
const groupCfg = getGroupVerifyConfig(current, groupIdNum);
|
|
267
275
|
const directImageUrls = extractImageUrls(event.message);
|
|
268
276
|
const quoteImageUrls = await extractQuoteImageUrls(event).catch(() => []);
|
|
269
277
|
const imageUrls =
|
|
@@ -275,14 +283,14 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
|
275
283
|
return;
|
|
276
284
|
}
|
|
277
285
|
const removedFile = groupCfg.promptImage;
|
|
278
|
-
const next = upsertGroupVerifyConfig(current,
|
|
286
|
+
const next = upsertGroupVerifyConfig(current, groupIdNum, {
|
|
279
287
|
customPrompt: "",
|
|
280
288
|
promptImage: "",
|
|
281
289
|
});
|
|
282
290
|
await setVerifyConfig(next);
|
|
283
|
-
await pruneGroupPromptImages(
|
|
291
|
+
await pruneGroupPromptImages(groupIdNum, []).catch(() => {});
|
|
284
292
|
ctx.logger.info(
|
|
285
|
-
`admin verify 关闭群 ${
|
|
293
|
+
`admin verify 关闭群 ${groupIdNum} 自定义入群提示,清理图片 ${removedFile}`,
|
|
286
294
|
);
|
|
287
295
|
await event.reply("已关闭本群自定义入群提示~", true);
|
|
288
296
|
return;
|
|
@@ -331,7 +339,7 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
|
331
339
|
let imageNote = "";
|
|
332
340
|
if (imageUrls.length) {
|
|
333
341
|
const targetUrl = imageUrls[0];
|
|
334
|
-
const savedImage = await saveRemoteImageAsPrompt(
|
|
342
|
+
const savedImage = await saveRemoteImageAsPrompt(groupIdNum, targetUrl);
|
|
335
343
|
if (savedImage) {
|
|
336
344
|
const previousImage = groupCfg.promptImage;
|
|
337
345
|
nextImage = savedImage.filename;
|
|
@@ -340,7 +348,7 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
|
340
348
|
: `图片已设置(${savedImage.filename})`;
|
|
341
349
|
if (previousImage) {
|
|
342
350
|
ctx.logger.info(
|
|
343
|
-
`admin verify 替换群 ${
|
|
351
|
+
`admin verify 替换群 ${groupIdNum} 入群提示图片:${previousImage} -> ${savedImage.filename}`,
|
|
344
352
|
);
|
|
345
353
|
}
|
|
346
354
|
} else {
|
|
@@ -348,12 +356,12 @@ export function registerVerifyCommands(options: VerifyCommandOptions) {
|
|
|
348
356
|
}
|
|
349
357
|
}
|
|
350
358
|
|
|
351
|
-
const next = upsertGroupVerifyConfig(current,
|
|
359
|
+
const next = upsertGroupVerifyConfig(current, groupIdNum, {
|
|
352
360
|
customPrompt: nextPrompt,
|
|
353
361
|
promptImage: nextImage,
|
|
354
362
|
});
|
|
355
363
|
await setVerifyConfig(next);
|
|
356
|
-
await pruneGroupPromptImages(
|
|
364
|
+
await pruneGroupPromptImages(groupIdNum, nextImage ? [nextImage] : []).catch(
|
|
357
365
|
() => {},
|
|
358
366
|
);
|
|
359
367
|
|