@2byte/tgbot-framework 1.0.14 → 1.0.16
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/package.json +1 -1
- package/src/core/App.ts +35 -6
- package/src/illumination/Artisan.ts +10 -39
- package/src/illumination/RunSectionRoute.ts +4 -0
- package/src/illumination/Section.ts +1 -0
- package/src/illumination/Telegraf2byteContext.ts +1 -0
- package/src/types.ts +1 -1
- package/src/user/UserModel.ts +14 -1
- package/src/workflow/services/MassSendApiService.ts +4 -5
- package/templates/TemplateSection.ts +37 -0
- package/templates/bot/package.json +1 -1
package/package.json
CHANGED
package/src/core/App.ts
CHANGED
|
@@ -74,7 +74,7 @@ export class App {
|
|
|
74
74
|
}
|
|
75
75
|
> = new Map();
|
|
76
76
|
|
|
77
|
-
private messageHandlers:
|
|
77
|
+
private messageHandlers: RunSectionRoute[] | CallableFunction<this>[] = [];
|
|
78
78
|
|
|
79
79
|
constructor() {
|
|
80
80
|
this.middlewares.push(this.mainMiddleware.bind(this));
|
|
@@ -162,13 +162,12 @@ export class App {
|
|
|
162
162
|
return this;
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
messageHandlers(handlers:
|
|
165
|
+
messageHandlers(handlers: RunSectionRoute[] | CallableFunction<this>[]): this {
|
|
166
166
|
this.app.messageHandlers = handlers;
|
|
167
167
|
return this;
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
/**
|
|
171
|
-
*
|
|
172
171
|
* @param keep Whether to keep section instances in memory after they are run.
|
|
173
172
|
* If true, sections will not be reloaded on each request, improving performance for frequently accessed sections.
|
|
174
173
|
* If false, sections will be reloaded each time they are accessed, ensuring the latest version is used.
|
|
@@ -433,16 +432,46 @@ export class App {
|
|
|
433
432
|
!ctx.userSession.stateAfterValidatedUserResponse
|
|
434
433
|
) {
|
|
435
434
|
this.messageHandlers.forEach(async (handler: any) => {
|
|
435
|
+
if (ctx.caught) {
|
|
436
|
+
this.debugLog("Message already caught by another handler, skipping remaining handlers.");
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const isHandlerRunSectionRoute = handler instanceof RunSectionRoute;
|
|
441
|
+
|
|
442
|
+
if (isHandlerRunSectionRoute) {
|
|
443
|
+
this.debugLog("Checking message handler section route:", handler);
|
|
444
|
+
await this.runSection(ctx, handler, {
|
|
445
|
+
cbBeforeRunMethod: async (sectionInstance: Section) => {
|
|
446
|
+
sectionInstance.runForMessageHandler = true;
|
|
447
|
+
},
|
|
448
|
+
});
|
|
449
|
+
if (ctx.caught) {
|
|
450
|
+
this.debugLog("Message handler route caught the message, skipping remaining handlers.");
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
436
455
|
const handlerIsClass =
|
|
437
456
|
typeof handler === "function" && /^\s*class\s+/.test(handler.toString());
|
|
438
457
|
const nameHandler = handlerIsClass
|
|
439
458
|
? handler.name
|
|
440
459
|
: handler.constructor?.name || "unknown";
|
|
441
460
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
if (handlerIsClass) {
|
|
461
|
+
if (handlerIsClass && !ctx.caught) {
|
|
462
|
+
this.debugLog(`Running message handler class ${nameHandler} for user ${ctx.user.username}`);
|
|
445
463
|
await new handler(this).handle(ctx);
|
|
464
|
+
if (ctx.caught) {
|
|
465
|
+
this.debugLog("Message handler class caught the message, skipping remaining handlers.");
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
} else if (!handlerIsClass && typeof handler === "function" && !ctx.caught) {
|
|
469
|
+
this.debugLog(`Running message handler function ${nameHandler} for user ${ctx.user.username}`);
|
|
470
|
+
await handler(ctx);
|
|
471
|
+
if (ctx.caught) {
|
|
472
|
+
this.debugLog("Message handler function caught the message, skipping remaining handlers.");
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
446
475
|
}
|
|
447
476
|
});
|
|
448
477
|
} else {
|
|
@@ -33,57 +33,28 @@ export class Artisan {
|
|
|
33
33
|
// Создаем файл секции
|
|
34
34
|
fs.writeFileSync(sectionPath, template);
|
|
35
35
|
console.log(`✅ Created section ${sectionName} at ${sectionPath}`);
|
|
36
|
+
console.log('To enable the section, add key it to the sections array in ' + process.cwd() + '/sectionList.ts');
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
/**
|
|
39
40
|
* Форматирует имя секции (первая буква заглавная, остальные строчные)
|
|
40
41
|
*/
|
|
41
42
|
private formatSectionName(name: string): string {
|
|
42
|
-
return name.charAt(0).toUpperCase() + name.slice(1)
|
|
43
|
+
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
/**
|
|
46
47
|
* Возвращает шаблон для новой секции
|
|
47
48
|
*/
|
|
48
49
|
private getSectionTemplate(name: string): string {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
"${name.toLowerCase()}.index": "index",
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
public sectionId = "${name.toLowerCase()}";
|
|
61
|
-
private mainInlineKeyboard: InlineKeyboard;
|
|
62
|
-
|
|
63
|
-
constructor(options: SectionOptions) {
|
|
64
|
-
super(options);
|
|
65
|
-
|
|
66
|
-
this.mainInlineKeyboard = this.makeInlineKeyboard([
|
|
67
|
-
[this.makeInlineButton("🏠 На главную", "home.index")],
|
|
68
|
-
]);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
public async up(): Promise<void> {}
|
|
72
|
-
public async down(): Promise<void> {}
|
|
73
|
-
public async setup(): Promise<void> {}
|
|
74
|
-
public async unsetup(): Promise<void> {}
|
|
75
|
-
|
|
76
|
-
async index() {
|
|
77
|
-
const message = \`
|
|
78
|
-
👋 Welcome to ${name} Section
|
|
79
|
-
\`;
|
|
80
|
-
|
|
81
|
-
await this.message(message)
|
|
82
|
-
.inlineKeyboard(this.mainInlineKeyboard)
|
|
83
|
-
.send();
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
`;
|
|
50
|
+
const filePath = path.join(__dirname, '../../templates', 'TemplateSection.ts');
|
|
51
|
+
let template = fs.readFileSync(filePath, 'utf-8');
|
|
52
|
+
const nameCamelCase = name.charAt(0).toLowerCase() + name.slice(1);
|
|
53
|
+
|
|
54
|
+
template = template.replace(/\$\{name\}/g, nameCamelCase);
|
|
55
|
+
template = template.replace(/\$\{commandName\}/g, name.toLowerCase());
|
|
56
|
+
template = template.replace(/TemplateSection/g, `${name}Section`);
|
|
57
|
+
return template;
|
|
87
58
|
}
|
|
88
59
|
|
|
89
60
|
/**
|
|
@@ -63,6 +63,10 @@ export class RunSectionRoute {
|
|
|
63
63
|
return this;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
static for(sectionId: string, methodName: string = 'index'): RunSectionRoute {
|
|
67
|
+
return new RunSectionRoute().section(sectionId).method(methodName);
|
|
68
|
+
}
|
|
69
|
+
|
|
66
70
|
hasTriggers(): boolean {
|
|
67
71
|
return this.runParams.triggers.length > 0;
|
|
68
72
|
}
|
|
@@ -15,6 +15,7 @@ export class Section {
|
|
|
15
15
|
static actionRoutes: { [key: string]: string };
|
|
16
16
|
public sectionId: string = "BaseSection";
|
|
17
17
|
public route: RunSectionRoute;
|
|
18
|
+
public runForMessageHandler: boolean = false;
|
|
18
19
|
protected ctx: Telegraf2byteContext;
|
|
19
20
|
protected bot: Telegraf<Telegraf2byteContext>;
|
|
20
21
|
protected app: App;
|
package/src/types.ts
CHANGED
package/src/user/UserModel.ts
CHANGED
|
@@ -47,10 +47,18 @@ export class UserModel extends Model {
|
|
|
47
47
|
return this.attributes;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
get id(): number
|
|
50
|
+
get id(): number {
|
|
51
51
|
return this.attributes.id;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
get tgUsername(): string {
|
|
55
|
+
return this.attributes.tg_username;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
get tgName(): string {
|
|
59
|
+
return this.attributes.tg_first_name + (this.attributes.tg_last_name ? " " + this.attributes.tg_last_name : "");
|
|
60
|
+
}
|
|
61
|
+
|
|
54
62
|
get lastMessageIds(): number[] {
|
|
55
63
|
return this.serviceAttributes.lastMessageIds;
|
|
56
64
|
}
|
|
@@ -153,6 +161,7 @@ export class UserModel extends Model {
|
|
|
153
161
|
|
|
154
162
|
const now = new Date().toISOString();
|
|
155
163
|
return UserModel.make({
|
|
164
|
+
id: 0,
|
|
156
165
|
tg_id: 0,
|
|
157
166
|
tg_username: tgUsername,
|
|
158
167
|
tg_first_name: tgUsername,
|
|
@@ -218,6 +227,10 @@ export class UserModel extends Model {
|
|
|
218
227
|
return this.attributes.role;
|
|
219
228
|
}
|
|
220
229
|
|
|
230
|
+
get roleIsAdmin(): boolean {
|
|
231
|
+
return this.attributes.role === 'admin';
|
|
232
|
+
}
|
|
233
|
+
|
|
221
234
|
get language(): string {
|
|
222
235
|
return this.attributes.language;
|
|
223
236
|
}
|
|
@@ -31,15 +31,14 @@ export class MassSendApiService extends ApiService<MassSendApiParams> {
|
|
|
31
31
|
this.app.debugLog("Received data for mass message:", receivedData);
|
|
32
32
|
|
|
33
33
|
let userIds: number[] = [];
|
|
34
|
-
let message: string = "Hello from MassSendApiService";
|
|
35
34
|
|
|
36
|
-
if (receivedData && typeof receivedData == "object") {
|
|
35
|
+
if (receivedData && typeof receivedData == "object" && receivedData.message) {
|
|
37
36
|
userIds = receivedData?.userIds || [];
|
|
38
|
-
message = receivedData?.message
|
|
37
|
+
const message = receivedData?.message;
|
|
38
|
+
|
|
39
|
+
this.sendMassMessage(userIds, message, receivedData.extra);
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
this.sendMassMessage(userIds, message, receivedData.extra);
|
|
42
|
-
|
|
43
42
|
return Response.json({ status: 200, body: "Mass message sending initiated." });
|
|
44
43
|
},
|
|
45
44
|
},
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Section } from "@2byte/tgbot-framework";
|
|
2
|
+
import { SectionOptions } from "@2byte/tgbot-framework";
|
|
3
|
+
import { InlineKeyboard } from "@2byte/tgbot-framework";
|
|
4
|
+
|
|
5
|
+
export default class TemplateSection extends Section {
|
|
6
|
+
static override command = "${commandName}";
|
|
7
|
+
static override description = "${name} section";
|
|
8
|
+
static override actionRoutes = {
|
|
9
|
+
"${name}.index": "index",
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
public override sectionId = "${name}";
|
|
13
|
+
private mainInlineKeyboard: InlineKeyboard;
|
|
14
|
+
|
|
15
|
+
constructor(options: SectionOptions) {
|
|
16
|
+
super(options);
|
|
17
|
+
|
|
18
|
+
this.mainInlineKeyboard = this.makeInlineKeyboard().addFootFixedButtons(
|
|
19
|
+
this.makeInlineButton("🏠 На главную", "home.index")
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public override async up(): Promise<void> {}
|
|
24
|
+
public override async down(): Promise<void> {}
|
|
25
|
+
public override async setup(): Promise<void> {}
|
|
26
|
+
public override async unsetup(): Promise<void> {}
|
|
27
|
+
|
|
28
|
+
async index() {
|
|
29
|
+
const message = `
|
|
30
|
+
👋 Welcome to ${this.ctx.user.attributes.tg_username} Section
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
await this.message(message)
|
|
34
|
+
.inlineKeyboard(this.mainInlineKeyboard)
|
|
35
|
+
.send();
|
|
36
|
+
}
|
|
37
|
+
}
|