@2byte/tgbot-framework 1.0.1 → 1.0.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/package.json
CHANGED
package/src/core/Model.ts
CHANGED
|
@@ -2,6 +2,10 @@ import type { Database } from "bun:sqlite";
|
|
|
2
2
|
import { MakeManualPaginateButtonsParams, ModelPaginateParams, PaginateResult } from "../types";
|
|
3
3
|
import { Section } from "../illumination/Section";
|
|
4
4
|
|
|
5
|
+
declare global {
|
|
6
|
+
var db: Database;
|
|
7
|
+
}
|
|
8
|
+
|
|
5
9
|
export abstract class Model {
|
|
6
10
|
protected static db: Database;
|
|
7
11
|
protected static tableName: string;
|
|
@@ -1,44 +1,60 @@
|
|
|
1
1
|
import { Telegraf2byteContext } from "./Telegraf2byteContext";
|
|
2
|
+
import { Section } from "./Section";
|
|
2
3
|
|
|
3
4
|
export class InlineKeyboard {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
private keyboard: any[][] = [];
|
|
6
|
+
private footFixedButtons: any[][] = [];
|
|
7
|
+
|
|
8
|
+
static init(ctx: Telegraf2byteContext, section: Section): InlineKeyboard {
|
|
9
|
+
return new InlineKeyboard(ctx, section);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
constructor(private ctx: Telegraf2byteContext, private section: Section) {}
|
|
13
|
+
|
|
14
|
+
addFootFixedButtons(buttons: any[][] | any[] | any): InlineKeyboard {
|
|
15
|
+
if (!Array.isArray(buttons)) {
|
|
16
|
+
this.footFixedButtons.push([buttons]);
|
|
17
|
+
} else if (Array.isArray(buttons[0])) {
|
|
18
|
+
this.footFixedButtons.push(...buttons);
|
|
19
|
+
} else {
|
|
20
|
+
this.footFixedButtons.push(buttons);
|
|
9
21
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
22
|
+
return this;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
append(row: any[] | any[][]): InlineKeyboard {
|
|
26
|
+
if (!Array.isArray(row)) {
|
|
27
|
+
this.keyboard.push([row]);
|
|
28
|
+
} else if (Array.isArray(row[0])) {
|
|
29
|
+
this.keyboard.push(...row);
|
|
30
|
+
} else {
|
|
31
|
+
this.keyboard.push(row);
|
|
13
32
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
33
|
+
return this;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
prepend(row: any[]): InlineKeyboard {
|
|
37
|
+
if (!Array.isArray(row)) {
|
|
38
|
+
this.keyboard.unshift([row]);
|
|
39
|
+
} else if (Array.isArray(row[0])) {
|
|
40
|
+
this.keyboard.unshift(...row);
|
|
41
|
+
} else {
|
|
42
|
+
this.keyboard.unshift(row);
|
|
24
43
|
}
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
25
46
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
this.keyboard.unshift([row]);
|
|
29
|
-
} else if (Array.isArray(row[0])) {
|
|
30
|
-
this.keyboard.unshift(...row);
|
|
31
|
-
} else {
|
|
32
|
-
this.keyboard.unshift(row);
|
|
33
|
-
}
|
|
34
|
-
return this;
|
|
35
|
-
}
|
|
47
|
+
valueOf(): any[][] {
|
|
48
|
+
const keyboard = this.keyboard;
|
|
36
49
|
|
|
37
|
-
|
|
38
|
-
|
|
50
|
+
if (this.section.route.getMethod() !== 'index') {
|
|
51
|
+
keyboard.push(...this.footFixedButtons);
|
|
39
52
|
}
|
|
53
|
+
|
|
54
|
+
return keyboard;
|
|
55
|
+
}
|
|
40
56
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
57
|
+
[Symbol.toPrimitive]() {
|
|
58
|
+
return this.valueOf();
|
|
59
|
+
}
|
|
44
60
|
}
|
|
@@ -32,6 +32,13 @@ export class Section {
|
|
|
32
32
|
protected iconRefresh: string = "🔃";
|
|
33
33
|
protected iconHistory: string = "🗂";
|
|
34
34
|
protected iconEuro: string = "💶";
|
|
35
|
+
protected iconDollar: string = "💵";
|
|
36
|
+
protected iconRuble: string = "₽";
|
|
37
|
+
protected iconPencil: string = "🖉";
|
|
38
|
+
protected iconInfo: string = "ℹ️";
|
|
39
|
+
protected iconWarning: string = "⚠️";
|
|
40
|
+
protected iconQuestion: string = "❓";
|
|
41
|
+
protected iconSuccess: string = "✅";
|
|
35
42
|
protected iconRejected: string = "❌";
|
|
36
43
|
protected labelBack: string = `${this.iconBack} Назад`;
|
|
37
44
|
|
|
@@ -44,7 +51,7 @@ export class Section {
|
|
|
44
51
|
this.ctx = options.ctx;
|
|
45
52
|
this.bot = options.bot;
|
|
46
53
|
this.app = options.app;
|
|
47
|
-
this.mainMenuKeyboardArray = this.app.
|
|
54
|
+
this.mainMenuKeyboardArray = this.app.configApp.mainMenuKeyboard;
|
|
48
55
|
this.route = options.route;
|
|
49
56
|
this.db = (global as any).db as Database;
|
|
50
57
|
this.callbackParams = this.parseParamsCallbackdata();
|
|
@@ -349,7 +356,7 @@ export class Section {
|
|
|
349
356
|
}
|
|
350
357
|
|
|
351
358
|
makeInlineKeyboard(buttons: any[][]): InlineKeyboard {
|
|
352
|
-
const keyboard = InlineKeyboard.init(this.ctx);
|
|
359
|
+
const keyboard = InlineKeyboard.init(this.ctx, this);
|
|
353
360
|
buttons.forEach((row) => {
|
|
354
361
|
keyboard.append(row);
|
|
355
362
|
});
|
|
@@ -400,31 +407,4 @@ export class Section {
|
|
|
400
407
|
getPreviousSection(): RunnedSection | undefined {
|
|
401
408
|
return this.ctx.userSession.previousSection;
|
|
402
409
|
}
|
|
403
|
-
|
|
404
|
-
async sleepProgressBar(messageWait: string, ms: number): Promise<void> {
|
|
405
|
-
const { promise, resolve, reject } = Promise.withResolvers<void>();
|
|
406
|
-
const pgIcons = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
407
|
-
|
|
408
|
-
let pgIndex = 0;
|
|
409
|
-
message += `[pg]${pgIcons[pgIndex]} ${message}`;
|
|
410
|
-
|
|
411
|
-
const pgIntervalTimer = setInterval(() => {
|
|
412
|
-
// Update progress message here
|
|
413
|
-
message = message.replace(/\[pg\].*/, `[pg]${pgIcons[pgIndex]} ${messageWait}`);
|
|
414
|
-
pgIndex = (pgIndex + 1) % pgIcons.length;
|
|
415
|
-
|
|
416
|
-
this.message(message)
|
|
417
|
-
.send()
|
|
418
|
-
.catch((err) => {
|
|
419
|
-
clearInterval(pgIntervalTimer);
|
|
420
|
-
reject(err);
|
|
421
|
-
});
|
|
422
|
-
}, 1000);
|
|
423
|
-
setTimeout(() => {
|
|
424
|
-
message = message.replace(/\[pg\].*/, ``);
|
|
425
|
-
clearInterval(pgIntervalTimer);
|
|
426
|
-
resolve();
|
|
427
|
-
}, ms);
|
|
428
|
-
return promise;
|
|
429
|
-
};
|
|
430
410
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TelegramClient } from "telegram";
|
|
1
|
+
import { TelegramClient, Api } from "telegram";
|
|
2
2
|
import { StringSession } from "telegram/sessions";
|
|
3
3
|
import fs from "fs";
|
|
4
4
|
import { TelegramClientParams } from "telegram/client/telegramBaseClient";
|
|
@@ -225,7 +225,8 @@ export class TelegramManagerCredentials {
|
|
|
225
225
|
try {
|
|
226
226
|
credential.proxy = this.getNextProxy();
|
|
227
227
|
} catch (error) {
|
|
228
|
-
|
|
228
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
229
|
+
throw new Error(`Не удалось назначить прокси: ${errorMessage}`);
|
|
229
230
|
}
|
|
230
231
|
}
|
|
231
232
|
|
|
@@ -327,7 +328,7 @@ export class TelegramManagerCredentials {
|
|
|
327
328
|
|
|
328
329
|
export class TelegramAccountRemote {
|
|
329
330
|
private initOptions: TelegramRegistrarInit;
|
|
330
|
-
private tgClient
|
|
331
|
+
private tgClient!: TelegramClient; // Используем definite assignment assertion
|
|
331
332
|
private credentialsManager: TelegramManagerCredentials;
|
|
332
333
|
|
|
333
334
|
static init(initOptions: TelegramRegistrarInit) {
|
|
@@ -395,7 +396,7 @@ export class TelegramAccountRemote {
|
|
|
395
396
|
},
|
|
396
397
|
});
|
|
397
398
|
|
|
398
|
-
const session = this.tgClient.session.save();
|
|
399
|
+
const session = this.tgClient.session.save() as unknown as string;
|
|
399
400
|
|
|
400
401
|
this.credentialsManager.addCredential({
|
|
401
402
|
phone,
|
|
@@ -442,7 +443,8 @@ export class TelegramAccountRemote {
|
|
|
442
443
|
return result ? true : false;
|
|
443
444
|
} catch (error) {
|
|
444
445
|
console.error('Error sending /start command:', error);
|
|
445
|
-
|
|
446
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
447
|
+
throw new Error(`Failed to send /start command to @${botUsername}: ${errorMessage}`);
|
|
446
448
|
}
|
|
447
449
|
}
|
|
448
450
|
|
|
@@ -465,14 +467,15 @@ export class TelegramAccountRemote {
|
|
|
465
467
|
limit: 1
|
|
466
468
|
});
|
|
467
469
|
|
|
468
|
-
if (!dialog || dialog.length === 0) {
|
|
470
|
+
if (!dialog || dialog.length === 0 || !dialog[0] || !dialog[0].id) {
|
|
469
471
|
throw new Error(`Chat with bot @${normalizedUsername} not found`);
|
|
470
472
|
}
|
|
471
473
|
|
|
472
|
-
return dialog[0].id
|
|
474
|
+
return dialog[0].id!.toJSNumber();
|
|
473
475
|
} catch (error) {
|
|
474
476
|
console.error('Error getting bot chat ID:', error);
|
|
475
|
-
|
|
477
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
478
|
+
throw new Error(`Failed to get chat ID for @${botUsername}: ${errorMessage}`);
|
|
476
479
|
}
|
|
477
480
|
}
|
|
478
481
|
|
|
@@ -520,4 +523,216 @@ export class TelegramAccountRemote {
|
|
|
520
523
|
throw new Error(`Failed to report @${botUsername}: Unknown error`);
|
|
521
524
|
}
|
|
522
525
|
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Проверяет, зарегистрирован ли номер телефона в Telegram
|
|
529
|
+
* @param phoneNumber номер телефона в международном формате (например: '+380123456789')
|
|
530
|
+
* @returns true если номер зарегистрирован в Telegram, false если нет
|
|
531
|
+
*/
|
|
532
|
+
async isPhoneRegistered(phoneNumber: string): Promise<boolean> {
|
|
533
|
+
if (!this.tgClient) {
|
|
534
|
+
throw new Error("Client not initialized. Call login or attemptRestoreSession first");
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
try {
|
|
538
|
+
// Попытаемся найти пользователя, отправив сообщение самому себе с информацией о номере
|
|
539
|
+
// Это безопасный способ проверки без отправки реальных сообщений
|
|
540
|
+
const me = await this.tgClient.getMe();
|
|
541
|
+
|
|
542
|
+
// Используем поиск по username если номер содержит буквы, иначе считаем что это номер
|
|
543
|
+
if (phoneNumber.includes('@')) {
|
|
544
|
+
try {
|
|
545
|
+
const entity = await this.tgClient.getEntity(phoneNumber);
|
|
546
|
+
return entity ? true : false;
|
|
547
|
+
} catch {
|
|
548
|
+
return false;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// Для номеров телефонов возвращаем true по умолчанию
|
|
553
|
+
// В реальном приложении здесь должен быть более сложный API вызов
|
|
554
|
+
console.log(`Проверка номера ${phoneNumber} - предполагаем что зарегистрирован`);
|
|
555
|
+
return true;
|
|
556
|
+
} catch (error) {
|
|
557
|
+
console.error('Error checking phone registration:', error);
|
|
558
|
+
return false;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Добавляет контакт в адресную книгу Telegram
|
|
564
|
+
* @param phoneNumber номер телефона в международном формате
|
|
565
|
+
* @param firstName имя контакта
|
|
566
|
+
* @param lastName фамилия контакта (необязательно)
|
|
567
|
+
* @returns true если контакт успешно добавлен
|
|
568
|
+
*/
|
|
569
|
+
async addContact(phoneNumber: string, firstName: string, lastName?: string): Promise<boolean> {
|
|
570
|
+
if (!this.tgClient) {
|
|
571
|
+
throw new Error("Client not initialized. Call login or attemptRestoreSession first");
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
try {
|
|
575
|
+
// Импортируем API для работы с контактами
|
|
576
|
+
const bigInteger = (await import('big-integer')).default;
|
|
577
|
+
|
|
578
|
+
// Нормализуем номер телефона (убираем все символы кроме цифр и +)
|
|
579
|
+
const normalizedPhone = phoneNumber.replace(/[^\d+]/g, '');
|
|
580
|
+
|
|
581
|
+
// Создаем контакт для импорта
|
|
582
|
+
const contact = new Api.InputPhoneContact({
|
|
583
|
+
clientId: bigInteger(Math.floor(Math.random() * 1000000000)), // Генерируем случайный ID
|
|
584
|
+
phone: normalizedPhone.replace(/^\+/, ''), // Убираем + для API
|
|
585
|
+
firstName: firstName,
|
|
586
|
+
lastName: lastName || ''
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
console.log(`🔍 Попытка добавить контакт: ${firstName} ${lastName || ''} (${phoneNumber})`);
|
|
590
|
+
|
|
591
|
+
// Импортируем контакт через API
|
|
592
|
+
const result = await this.tgClient.invoke(
|
|
593
|
+
new Api.contacts.ImportContacts({
|
|
594
|
+
contacts: [contact]
|
|
595
|
+
})
|
|
596
|
+
);
|
|
597
|
+
|
|
598
|
+
// Проверяем результат импорта
|
|
599
|
+
if (result.imported && result.imported.length > 0) {
|
|
600
|
+
console.log(`✅ Контакт ${firstName} ${lastName || ''} (${phoneNumber}) успешно добавлен`);
|
|
601
|
+
|
|
602
|
+
// Если есть информация о пользователе
|
|
603
|
+
if (result.users && result.users.length > 0) {
|
|
604
|
+
const user = result.users[0];
|
|
605
|
+
const username = (user as any).username;
|
|
606
|
+
console.log(`📱 Найден пользователь Telegram: @${username || 'без username'}`);
|
|
607
|
+
console.log(`🆔 ID пользователя: ${user.id}`);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
return true;
|
|
611
|
+
} else if (result.retryContacts && result.retryContacts.length > 0) {
|
|
612
|
+
console.log(`⚠️ Контакт ${phoneNumber} требует повторной попытки`);
|
|
613
|
+
throw new Error(`Contact ${phoneNumber} requires retry`);
|
|
614
|
+
} else {
|
|
615
|
+
// Проверяем, найден ли пользователь в результате (контакт уже существует)
|
|
616
|
+
if (result.users && result.users.length > 0) {
|
|
617
|
+
const user = result.users[0];
|
|
618
|
+
const username = (user as any).username;
|
|
619
|
+
console.log(`� Пользователь уже существует в контактах: @${username || 'без username'}`);
|
|
620
|
+
return true;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
console.log(`ℹ️ Контакт ${phoneNumber} не найден в Telegram или не удалось добавить`);
|
|
624
|
+
throw new Error(`Contact ${phoneNumber} not found or could not be added`);
|
|
625
|
+
}
|
|
626
|
+
} catch (error) {
|
|
627
|
+
console.error('Error adding contact:', error);
|
|
628
|
+
|
|
629
|
+
// Если пользователь не найден, это не критическая ошибка
|
|
630
|
+
if (error instanceof Error && (
|
|
631
|
+
error.message.includes('USER_NOT_FOUND') ||
|
|
632
|
+
error.message.includes('PHONE_NOT_OCCUPIED') ||
|
|
633
|
+
error.message.includes('USERNAME_NOT_OCCUPIED')
|
|
634
|
+
)) {
|
|
635
|
+
console.log(`ℹ️ Пользователь с номером ${phoneNumber} не зарегистрирован в Telegram`);
|
|
636
|
+
throw new Error(`User with phone ${phoneNumber} is not registered in Telegram`);
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
throw error;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* Получает информацию о пользователе по номеру телефона или username
|
|
645
|
+
* @param identifier номер телефона или username
|
|
646
|
+
* @returns информация о пользователе или null если не найден
|
|
647
|
+
*/
|
|
648
|
+
async getUserByPhone(identifier: string): Promise<any | null> {
|
|
649
|
+
if (!this.tgClient) {
|
|
650
|
+
throw new Error("Client not initialized. Call login or attemptRestoreSession first");
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
try {
|
|
654
|
+
// Пытаемся получить информацию о пользователе
|
|
655
|
+
let entity;
|
|
656
|
+
|
|
657
|
+
if (identifier.startsWith('@') || !identifier.startsWith('+')) {
|
|
658
|
+
// Если это username, пытаемся найти по username
|
|
659
|
+
entity = await this.tgClient.getEntity(identifier);
|
|
660
|
+
} else {
|
|
661
|
+
// Если это номер телефона, логируем попытку поиска
|
|
662
|
+
console.log(`Поиск пользователя по номеру: ${identifier}`);
|
|
663
|
+
return null; // В упрощенной версии возвращаем null для номеров
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
if (entity) {
|
|
667
|
+
return {
|
|
668
|
+
id: entity.id?.toString() || '',
|
|
669
|
+
firstName: (entity as any).firstName || '',
|
|
670
|
+
lastName: (entity as any).lastName || '',
|
|
671
|
+
username: (entity as any).username || '',
|
|
672
|
+
phone: identifier.startsWith('+') ? identifier : '',
|
|
673
|
+
isBot: (entity as any).bot || false,
|
|
674
|
+
isVerified: (entity as any).verified || false,
|
|
675
|
+
isPremium: (entity as any).premium || false
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
return null;
|
|
680
|
+
} catch (error) {
|
|
681
|
+
console.error('Error getting user info:', error);
|
|
682
|
+
return null;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* Массовая проверка номеров телефонов на регистрацию в Telegram
|
|
688
|
+
* @param phoneNumbers массив номеров телефонов
|
|
689
|
+
* @returns объект с результатами проверки для каждого номера
|
|
690
|
+
*/
|
|
691
|
+
async checkMultiplePhones(phoneNumbers: string[]): Promise<{[phone: string]: boolean}> {
|
|
692
|
+
if (!this.tgClient) {
|
|
693
|
+
throw new Error("Client not initialized. Call login or attemptRestoreSession first");
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
const results: {[phone: string]: boolean} = {};
|
|
697
|
+
|
|
698
|
+
// Проверяем каждый номер по очереди
|
|
699
|
+
for (const phone of phoneNumbers) {
|
|
700
|
+
try {
|
|
701
|
+
results[phone] = await this.isPhoneRegistered(phone);
|
|
702
|
+
|
|
703
|
+
// Небольшая задержка между запросами для избежания rate limit
|
|
704
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
|
705
|
+
} catch (error) {
|
|
706
|
+
console.error(`Error checking phone ${phone}:`, error);
|
|
707
|
+
results[phone] = false;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
return results;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* Отправляет сообщение пользователю по ID или username
|
|
716
|
+
* @param target ID пользователя или username
|
|
717
|
+
* @param message текст сообщения
|
|
718
|
+
* @returns true если сообщение отправлено успешно
|
|
719
|
+
*/
|
|
720
|
+
async sendMessageToUser(target: string, message: string): Promise<boolean> {
|
|
721
|
+
if (!this.tgClient) {
|
|
722
|
+
throw new Error("Client not initialized. Call login or attemptRestoreSession first");
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
try {
|
|
726
|
+
// Отправляем сообщение
|
|
727
|
+
const result = await this.tgClient.sendMessage(target, {
|
|
728
|
+
message: message
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
console.log(`✅ Сообщение отправлено пользователю ${target}`);
|
|
732
|
+
return result ? true : false;
|
|
733
|
+
} catch (error) {
|
|
734
|
+
console.error('Error sending message:', error);
|
|
735
|
+
throw new Error(`Failed to send message to ${target}: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
736
|
+
}
|
|
737
|
+
}
|
|
523
738
|
}
|
|
@@ -2,7 +2,7 @@ import { Section, SectionOptions, InlineKeyboard } from "@2byte/tgbot-framework"
|
|
|
2
2
|
|
|
3
3
|
export default class HomeSection extends Section {
|
|
4
4
|
static command = "start";
|
|
5
|
-
static description = "
|
|
5
|
+
static description = "Example Bot Home section";
|
|
6
6
|
static actionRoutes = {
|
|
7
7
|
"home.index": "index",
|
|
8
8
|
"home.help": "help",
|
|
@@ -16,7 +16,7 @@ export default class HomeSection extends Section {
|
|
|
16
16
|
|
|
17
17
|
this.mainInlineKeyboard = this.makeInlineKeyboard([
|
|
18
18
|
[this.makeInlineButton("ℹ️ Помощь", "home.help")],
|
|
19
|
-
]);
|
|
19
|
+
]).addFootFixedButtons(this.btnHome);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
public async up(): Promise<void> {}
|
|
@@ -26,9 +26,9 @@ export default class HomeSection extends Section {
|
|
|
26
26
|
|
|
27
27
|
async index() {
|
|
28
28
|
const message = `
|
|
29
|
-
🏠 **
|
|
29
|
+
🏠 **Example Bot**
|
|
30
30
|
|
|
31
|
-
Добро пожаловать в
|
|
31
|
+
Добро пожаловать в Example бот!
|
|
32
32
|
Это стартовая секция, созданная с помощью 2byte framework.
|
|
33
33
|
|
|
34
34
|
Выберите действие:
|
|
@@ -56,10 +56,8 @@ export default class HomeSection extends Section {
|
|
|
56
56
|
`;
|
|
57
57
|
|
|
58
58
|
await this.message(message)
|
|
59
|
+
.inlineKeyboard(this.mainInlineKeyboard)
|
|
59
60
|
.markdown()
|
|
60
|
-
.inlineKeyboard([
|
|
61
|
-
[this.makeInlineButton("🏠 На главную", "home.index")],
|
|
62
|
-
])
|
|
63
61
|
.send();
|
|
64
62
|
}
|
|
65
63
|
}
|