Edit on GitHub

src.handlers.info

Информационные сообщения

  1"""Информационные сообщения"""
  2
  3import logging
  4from contextlib import suppress
  5from datetime import timedelta
  6from typing import Union
  7
  8from aiogram import Bot, F, Router
  9from aiogram.exceptions import TelegramBadRequest
 10from aiogram.filters.command import Command
 11from aiogram.types import CallbackQuery, Message
 12from aiogram.utils.formatting import Bold, as_list, as_marked_section
 13
 14import kb
 15import text
 16from core.config import settings
 17from core.err import bot_except
 18from core.exceptions import BaseBotError, DatabaseError, WireguardError
 19from db.models import UserData
 20from db.utils import get_user, test_server_speed
 21from handlers.utils import find_user
 22from wg.utils import WgServerTools
 23
 24logger = logging.getLogger()
 25router = Router()
 26router.message.filter(F.chat.type == "private")
 27
 28
 29async def more_help_info(callback: CallbackQuery):
 30    """Отправляет дополнительную информацию о помощи.
 31
 32    Args:
 33        callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.
 34
 35    Отправляет сообщение с предложением задать дополнительные вопросы и кнопкой для доступа к меню помощи.
 36    """
 37    await callback.message.answer(
 38        "Если у вас есть дополнительные вопросы, не стесняйтесь спрашивать! Мы здесь, чтобы помочь вам. 🚀",
 39        reply_markup=kb.get_help_menu(
 40            callback.from_user.full_name, callback.from_user.id
 41        ),
 42    )
 43
 44
 45async def change_help_page(message: Message, pages: list, page: int, prefix: str):
 46    """Изменяет страницу помощи.
 47
 48    Args:
 49        message (Message): Сообщение, которое будет изменено.
 50        pages (list): Список страниц помощи.
 51        page (int): Индекс текущей страницы.
 52        prefix (str): Префикс для кнопок навигации.
 53
 54    Обновляет текст сообщения с новой страницей помощи и кнопками навигации.
 55    """
 56    with suppress(TelegramBadRequest):
 57        await message.edit_text(
 58            pages[page], reply_markup=kb.get_help_book_keyboard(pages, page, prefix)
 59        )
 60
 61
 62async def post_help_book(
 63    callback: CallbackQuery, book: list, step: str, start_message: str, prefix: str
 64):
 65    """Отправляет книгу помощи пользователю.
 66
 67    Args:
 68        callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.
 69        book (list): Список шагов помощи.
 70        step (str): Текущий шаг.
 71        start_message (str): Сообщение, отправляемое в начале.
 72        prefix (str): Префикс для кнопок навигации.
 73
 74    Отправляет сообщения с шагами помощи в зависимости от текущего шага.
 75    """
 76    if step == "start":
 77        await callback.message.answer(start_message)
 78
 79        await callback.message.answer(
 80            book[0],
 81            reply_markup=kb.get_help_book_keyboard(pages=book, page=0, prefix=prefix),
 82        )
 83    elif step.isdigit():
 84        await change_help_page(
 85            callback.message, pages=book, page=int(step), prefix=prefix
 86        )
 87    else:
 88        for step in book:
 89            await callback.message.answer(step)
 90        await more_help_info(callback)
 91
 92
 93@router.message(Command("help"))
 94@router.message(F.text == "Помощь")
 95@router.callback_query(F.data == "main_help")
 96@bot_except
 97async def help_me(trigger: Union[Message, CallbackQuery]):
 98    """Обработчик команды помощи.
 99
100    Args:
101        trigger (Union[Message, CallbackQuery]): Сообщение или событие обратного вызова, инициировавшее команду.
102
103    Отправляет сообщение с предложением помощи и кнопками для доступа к меню помощи.
104    """
105    await getattr(trigger, "message", trigger).answer(
106        "Чем вам помочь?",
107        reply_markup=kb.get_help_menu(
108            trigger.from_user.full_name, trigger.from_user.id
109        ),
110    )
111
112
113@router.callback_query(F.data == "bot_info")
114@bot_except
115async def bot_info(callback: CallbackQuery):
116    """Отправляет информацию о боте.
117
118    Args:
119        callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.
120
121    Отправляет сообщение с информацией о боте и кнопкой для доступа к дополнительной помощи.
122    """
123    await callback.message.answer(text.BOT_INFO, reply_markup=kb.static_join_button)
124    await more_help_info(callback)
125
126
127@router.callback_query(F.data.startswith("first_help_info_"))
128@bot_except
129async def next_help(callback: CallbackQuery):
130    """Обработчик перехода к следующему шагу помощи.
131
132    Args:
133        callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.
134
135    Отправляет сообщения с шагами помощи в зависимости от текущего шага.
136    """
137    current_step: str = callback.data.split("_")[-1]
138
139    await post_help_book(
140        callback,
141        book=text.BOT_STEPS,
142        step=current_step,
143        start_message="🤖 <b>Что делать дальше? Вот краткий алгоритм работы с нашим ботом и WireGuard:</b>",
144        prefix="first_help_info",
145    )
146
147
148@router.callback_query(F.data == "wg_help_info")
149@bot_except
150async def wg_help(callback: CallbackQuery):
151    """Отправляет информацию о платформе для установки WireGuard.
152
153    Args:
154        callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.
155
156    Отправляет сообщение с вопросом о платформе для установки WireGuard и кнопками для выбора.
157    """
158    await callback.message.answer(
159        "На какую платформу вы хотите установить WireGuard?",
160        reply_markup=kb.static_wg_platform_keyboard,
161    )
162
163
164@router.callback_query(F.data.startswith("wg_help_info_"))
165@bot_except
166async def wg_help_platform(callback: CallbackQuery):
167    """Обработчик помощи по установке WireGuard на выбранной платформе.
168
169    Args:
170        callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.
171
172    Отправляет сообщения с шагами помощи для установки WireGuard на выбранной платформе.
173    """
174    *_, current_platform, current_step = callback.data.split("_")
175
176    await post_help_book(
177        callback,
178        book=text.WG_STEPS[current_platform],
179        step=current_step,
180        start_message=f"🛠️ <b>Настройка WireGuard на {current_platform}:</b>",
181        prefix=f"wg_help_info_{current_platform}",
182    )
183
184
185@router.callback_query(F.data.startswith("error_help_info"))
186@bot_except
187async def error_help(callback: CallbackQuery):
188    """Обработчик помощи по устранению ошибок.
189
190    Args:
191        callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.
192
193    Отправляет сообщения с шагами помощи для устранения ошибок.
194    """
195    current_step: str = callback.data.split("_")[-1]
196
197    await post_help_book(
198        callback,
199        book=text.BOT_ERROR_STEP,
200        step=current_step,
201        start_message="📋 <b>Не волнуйтесь, вот инструкции по устранению проблем с DanVPN</b>",
202        prefix="error_help_info",
203    )
204
205
206@router.message(Command("time"))
207@bot_except
208async def started(message: Message, started_at):
209    """Отправляет время начала работы бота.
210
211    Args:
212        message (Message): Сообщение, инициировавшее команду.
213        started_at: Время начала работы бота.
214
215    Отправляет сообщение с временем начала работы бота.
216    """
217    await message.answer(f"Время начала работы бота: {started_at}")
218
219
220@router.message(Command("id"))
221@router.callback_query(F.data == "user_id_info")
222@bot_except
223async def start_bot(trigger: Union[Message, CallbackQuery]):
224    """Отправляет ID пользователя.
225
226    Args:
227        trigger (Union[Message, CallbackQuery]): Сообщение или событие обратного вызова, инициировавшее команду.
228
229    Отправляет сообщение с Telegram ID пользователя.
230    """
231    await getattr(trigger, "message", trigger).answer(
232        f'Ваш Telegram ID\n\n<span class="tg-spoiler">{trigger.from_user.id}</span>'
233    )
234
235
236@router.message(Command("cmd"))
237@router.message(Command("commands"))
238@router.message(F.text == "Команды")
239@router.callback_query(F.data == "cmd_help_info")
240@bot_except
241async def commands_list(trigger: Union[Message, CallbackQuery]):
242    """Отправляет список доступных команд.
243
244    Args:
245        trigger (Union[Message, CallbackQuery]): Сообщение или событие обратного вызова, инициировавшее команду.
246
247    Отправляет сообщение с перечислением доступных команд и их описанием.
248    """
249    help_t = as_list(
250        Bold("Запуск:"),
251        "/start - запуск (перезагрузка) бота",
252        Bold("Действия с аккаунтом:"),
253        as_marked_section(
254            "/account | /app - Основной функционал аккаунта",
255            "/reg - Регистрация в БД Бота",
256            "/freeze - Заморозить аккаунт",
257            "/recover - Разморозить аккаунт",
258            "/chat - Получить доступ в клиентский чат",
259            marker="~ ",
260        ),
261        Bold("Действия с конфигурациями:"),
262        as_marked_section(
263            "/me | /config - данные о моих конфигурациях wireguard",
264            "/create - создать конфигурацию",
265            marker="~ ",
266        ),
267        Bold("Действия с подпиской:"),
268        as_marked_section(
269            "/sub - Купить подписку",
270            "/refund - Сделать запрос на возврат средств",
271            "/history - История транзакций",
272            marker="~ ",
273        ),
274        Bold("Информация:"),
275        as_marked_section(
276            "/help - Помощь",
277            "/cmd - Список всех команд",
278            "/admin - функционал администратора",
279            "/bug - Доложить о баге",
280            "/id - Ваш Telegram ID",
281            "/time - время запуска бота",
282            marker="~ ",
283        ),
284        as_marked_section(
285            Bold("Расширенные возможности (тарифы от расширенного и выше):"),
286            "/server - Анализ работы сервера",
287            "/speed - Максимально доступная скорость VPN на данный момент",
288            "/mute - Отключить уведомления",
289        ),
290    )
291    await getattr(trigger, "message", trigger).answer(**help_t.as_kwargs())
292
293
294@router.callback_query(F.data == "freeze_info")
295@bot_except
296async def freeze_config_info(callback: CallbackQuery):
297    """Отправляет информацию о заморозке конфигураций.
298
299    Args:
300        callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.
301
302    Отправляет сообщение с информацией о том, как заморозить конфигурации и что делать в случае проблем.
303    """
304    await callback.message.answer(
305        "Конфигурации замораживаются, когда становятся недоступными. "
306        "\n\nПроверьте, достаточно ли средств на вашем счете? Соответствует ли количество ваших конфигураций вашему тарифу? "
307        "Возможно недавно произошли изменения в вашем тарифе, подождите несколько минут и попробуйте снова."
308        "\n\nЕсли вам все равно не понятно, почему ваша конфигурация заблокирована, воспользуйтесь командой /bug и сообщите о вашей проблеме."
309    )
310
311
312@router.callback_query(F.data == "freeze_account_info")
313@bot_except
314async def freeze_user_info(callback: CallbackQuery):
315    """Отправляет информацию о заморозке аккаунта.
316
317    Args:
318        callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.
319
320    Отправляет сообщение с информацией о том, как заморозить аккаунт и его последствиях.
321    """
322    await callback.message.answer(
323        "Заморозка аккаунта подразумевает приостановку ежедневных списаний "
324        "и, соответственно, блокировку всех созданных конфигураций."
325        "\nРазморозить свой аккаунт можно в меню /app. После разморозки восстановление конфигураций произойдет в течение 1 минуты."
326        "\n\n<b>Стоимость услуги равна одному ежедневному списанию вашего тарифа!</b>"
327        "\n<b>Разблокировка бесплатна.</b>",
328        reply_markup=kb.freeze_user_button,
329    )
330
331
332@router.message(Command("server"))
333@router.callback_query(F.data == "server_status")
334@bot_except
335async def server_status(trigger: Union[Message, CallbackQuery], bot: Bot):
336    """Отправляет информацию о состоянии сервера.
337
338    Args:
339        trigger (Union[Message, CallbackQuery]): Сообщение или событие обратного вызова, инициировавшее команду.
340        bot (Bot): Экземпляр бота для выполнения действий.
341
342    Отправляет сообщение с текущим состоянием сервера и его загрузкой.
343    """
344    await bot.send_chat_action(trigger.from_user.id, "typing")
345
346    user_data: UserData = await find_user(trigger)
347    if not user_data:
348        return
349    elif user_data.stage < 2:
350        await getattr(trigger, "message", trigger).answer(
351            "Команда заблокирована. Выберите тариф от 'Расширенного' или выше."
352        )
353        return
354
355    try:
356        wg = WgServerTools()
357
358        server_status = await wg.get_server_status()
359        cpu_usage = await wg.get_server_cpu_usage()
360
361    except WireguardError:
362        await getattr(trigger, "message", trigger).answer(text.WG_ERROR)
363
364    else:
365        server_data = (
366            "Текущие параметры сервера:\n\n"
367            f"🖥 Сервер:        <b>{server_status.capitalize()}</b>\n\n"
368            f"🦾 СPU usage:  <b>{cpu_usage}</b>"
369        )
370
371        await getattr(trigger, "message", trigger).answer(server_data)
372
373
374@router.message(Command("speed"))
375@router.callback_query(F.data == "server_speed")
376@bot_except
377async def server_speed(trigger: Union[Message, CallbackQuery], bot: Bot):
378    """Отправляет информацию о скорости сервера.
379
380    Args:
381        trigger (Union[Message, CallbackQuery]): Сообщение или событие обратного вызова, инициировавшее команду.
382        bot (Bot): Экземпляр бота для выполнения действий.
383
384    Отправляет сообщение с текущей доступной скоростью интернет-соединения по VPN.
385    """
386    await bot.send_chat_action(trigger.from_user.id, "typing")
387
388    user_data: UserData = await find_user(trigger)
389    if not user_data:
390        return
391    elif user_data.stage < 2:
392        await getattr(trigger, "message", trigger).answer(
393            "Команда заблокирована. Выберите тариф от 'Расширенного' или выше."
394        )
395        return
396
397    try:
398        server_speed_in, server_speed_out = await test_server_speed()
399
400    except WireguardError:
401        await getattr(trigger, "message", trigger).answer(
402            text.WG_ERROR, show_alert=True
403        )
404    except DatabaseError:
405        await trigger.answer(text=text.DB_ERROR, show_alert=True)
406    except BaseBotError:
407        await trigger.answer(
408            text="Ошибка измерения пропускной способности. Попробуйте позже.",
409            show_alert=True,
410        )
411
412    else:
413        server_data = (
414            "Текущая максимально доступная скорость интернет соединения по VPN:\n\n"
415            f"📥 Скачивание:  <b>{round(server_speed_in/1048576, 2)} Мбит/с</b>\n\n"
416            f"📤 Загрузка:        <b>{round(server_speed_out/1048576, 2)} Мбит/с</b>"
417        )
418
419        await getattr(trigger, "message", trigger).answer(server_data)
420
421
422@router.message(Command("chat"))
423@router.message(F.text == "Чат")
424@router.callback_query(F.data == "invite_to_chat")
425@bot_except
426async def get_chat_invite(trigger: Union[Message, CallbackQuery], bot: Bot):
427    """Отправляет приглашение в чат.
428
429    Args:
430        trigger (Union[Message, CallbackQuery]): Сообщение или событие обратного вызова, инициировавшее команду.
431        bot (Bot): Экземпляр бота для выполнения действий.
432
433    Отправляет сообщение с ссылкой на чат для зарегистрированных пользователей.
434    """
435    user_data = await get_user(trigger.from_user.id)
436
437    if user_data is None:
438        await getattr(trigger, "message", trigger).answer(
439            "Чат доступен только зарегистрированным пользователям. "
440            "Для начала выполните команду /reg"
441        )
442    else:
443        try:
444            link = await bot.create_chat_invite_link(
445                settings.BOT_CHAT, "chat", timedelta(hours=12), member_limit=1
446            )
447        except TelegramBadRequest:
448            logger.exception("Недоступен пользовательский чат")
449        else:
450            await getattr(trigger, "message", trigger).answer(
451                "🎉Поздравляем! Вам открыт доступ в клиентский чат.",
452                reply_markup=kb.get_chat_button(link.invite_link),
453            )
logger = <RootLogger root (DEBUG)>
router = <Router '0x7f23dac572f0'>
async def more_help_info(callback: aiogram.types.callback_query.CallbackQuery):
30async def more_help_info(callback: CallbackQuery):
31    """Отправляет дополнительную информацию о помощи.
32
33    Args:
34        callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.
35
36    Отправляет сообщение с предложением задать дополнительные вопросы и кнопкой для доступа к меню помощи.
37    """
38    await callback.message.answer(
39        "Если у вас есть дополнительные вопросы, не стесняйтесь спрашивать! Мы здесь, чтобы помочь вам. 🚀",
40        reply_markup=kb.get_help_menu(
41            callback.from_user.full_name, callback.from_user.id
42        ),
43    )

Отправляет дополнительную информацию о помощи.

Arguments:
  • callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.

Отправляет сообщение с предложением задать дополнительные вопросы и кнопкой для доступа к меню помощи.

async def change_help_page( message: aiogram.types.message.Message, pages: list, page: int, prefix: str):
46async def change_help_page(message: Message, pages: list, page: int, prefix: str):
47    """Изменяет страницу помощи.
48
49    Args:
50        message (Message): Сообщение, которое будет изменено.
51        pages (list): Список страниц помощи.
52        page (int): Индекс текущей страницы.
53        prefix (str): Префикс для кнопок навигации.
54
55    Обновляет текст сообщения с новой страницей помощи и кнопками навигации.
56    """
57    with suppress(TelegramBadRequest):
58        await message.edit_text(
59            pages[page], reply_markup=kb.get_help_book_keyboard(pages, page, prefix)
60        )

Изменяет страницу помощи.

Arguments:
  • message (Message): Сообщение, которое будет изменено.
  • pages (list): Список страниц помощи.
  • page (int): Индекс текущей страницы.
  • prefix (str): Префикс для кнопок навигации.

Обновляет текст сообщения с новой страницей помощи и кнопками навигации.

async def post_help_book( callback: aiogram.types.callback_query.CallbackQuery, book: list, step: str, start_message: str, prefix: str):
63async def post_help_book(
64    callback: CallbackQuery, book: list, step: str, start_message: str, prefix: str
65):
66    """Отправляет книгу помощи пользователю.
67
68    Args:
69        callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.
70        book (list): Список шагов помощи.
71        step (str): Текущий шаг.
72        start_message (str): Сообщение, отправляемое в начале.
73        prefix (str): Префикс для кнопок навигации.
74
75    Отправляет сообщения с шагами помощи в зависимости от текущего шага.
76    """
77    if step == "start":
78        await callback.message.answer(start_message)
79
80        await callback.message.answer(
81            book[0],
82            reply_markup=kb.get_help_book_keyboard(pages=book, page=0, prefix=prefix),
83        )
84    elif step.isdigit():
85        await change_help_page(
86            callback.message, pages=book, page=int(step), prefix=prefix
87        )
88    else:
89        for step in book:
90            await callback.message.answer(step)
91        await more_help_info(callback)

Отправляет книгу помощи пользователю.

Arguments:
  • callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.
  • book (list): Список шагов помощи.
  • step (str): Текущий шаг.
  • start_message (str): Сообщение, отправляемое в начале.
  • prefix (str): Префикс для кнопок навигации.

Отправляет сообщения с шагами помощи в зависимости от текущего шага.

@router.message(Command('help'))
@router.message(F.text == 'Помощь')
@router.callback_query(F.data == 'main_help')
@bot_except
async def help_me( trigger: Union[aiogram.types.message.Message, aiogram.types.callback_query.CallbackQuery]):
 94@router.message(Command("help"))
 95@router.message(F.text == "Помощь")
 96@router.callback_query(F.data == "main_help")
 97@bot_except
 98async def help_me(trigger: Union[Message, CallbackQuery]):
 99    """Обработчик команды помощи.
100
101    Args:
102        trigger (Union[Message, CallbackQuery]): Сообщение или событие обратного вызова, инициировавшее команду.
103
104    Отправляет сообщение с предложением помощи и кнопками для доступа к меню помощи.
105    """
106    await getattr(trigger, "message", trigger).answer(
107        "Чем вам помочь?",
108        reply_markup=kb.get_help_menu(
109            trigger.from_user.full_name, trigger.from_user.id
110        ),
111    )

Обработчик команды помощи.

Arguments:
  • trigger (Union[Message, CallbackQuery]): Сообщение или событие обратного вызова, инициировавшее команду.

Отправляет сообщение с предложением помощи и кнопками для доступа к меню помощи.

@router.callback_query(F.data == 'bot_info')
@bot_except
async def bot_info(callback: aiogram.types.callback_query.CallbackQuery):
114@router.callback_query(F.data == "bot_info")
115@bot_except
116async def bot_info(callback: CallbackQuery):
117    """Отправляет информацию о боте.
118
119    Args:
120        callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.
121
122    Отправляет сообщение с информацией о боте и кнопкой для доступа к дополнительной помощи.
123    """
124    await callback.message.answer(text.BOT_INFO, reply_markup=kb.static_join_button)
125    await more_help_info(callback)

Отправляет информацию о боте.

Arguments:
  • callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.

Отправляет сообщение с информацией о боте и кнопкой для доступа к дополнительной помощи.

@router.callback_query(F.data.startswith('first_help_info_'))
@bot_except
async def next_help(callback: aiogram.types.callback_query.CallbackQuery):
128@router.callback_query(F.data.startswith("first_help_info_"))
129@bot_except
130async def next_help(callback: CallbackQuery):
131    """Обработчик перехода к следующему шагу помощи.
132
133    Args:
134        callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.
135
136    Отправляет сообщения с шагами помощи в зависимости от текущего шага.
137    """
138    current_step: str = callback.data.split("_")[-1]
139
140    await post_help_book(
141        callback,
142        book=text.BOT_STEPS,
143        step=current_step,
144        start_message="🤖 <b>Что делать дальше? Вот краткий алгоритм работы с нашим ботом и WireGuard:</b>",
145        prefix="first_help_info",
146    )

Обработчик перехода к следующему шагу помощи.

Arguments:
  • callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.

Отправляет сообщения с шагами помощи в зависимости от текущего шага.

@router.callback_query(F.data == 'wg_help_info')
@bot_except
async def wg_help(callback: aiogram.types.callback_query.CallbackQuery):
149@router.callback_query(F.data == "wg_help_info")
150@bot_except
151async def wg_help(callback: CallbackQuery):
152    """Отправляет информацию о платформе для установки WireGuard.
153
154    Args:
155        callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.
156
157    Отправляет сообщение с вопросом о платформе для установки WireGuard и кнопками для выбора.
158    """
159    await callback.message.answer(
160        "На какую платформу вы хотите установить WireGuard?",
161        reply_markup=kb.static_wg_platform_keyboard,
162    )

Отправляет информацию о платформе для установки WireGuard.

Arguments:
  • callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.

Отправляет сообщение с вопросом о платформе для установки WireGuard и кнопками для выбора.

@router.callback_query(F.data.startswith('wg_help_info_'))
@bot_except
async def wg_help_platform(callback: aiogram.types.callback_query.CallbackQuery):
165@router.callback_query(F.data.startswith("wg_help_info_"))
166@bot_except
167async def wg_help_platform(callback: CallbackQuery):
168    """Обработчик помощи по установке WireGuard на выбранной платформе.
169
170    Args:
171        callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.
172
173    Отправляет сообщения с шагами помощи для установки WireGuard на выбранной платформе.
174    """
175    *_, current_platform, current_step = callback.data.split("_")
176
177    await post_help_book(
178        callback,
179        book=text.WG_STEPS[current_platform],
180        step=current_step,
181        start_message=f"🛠️ <b>Настройка WireGuard на {current_platform}:</b>",
182        prefix=f"wg_help_info_{current_platform}",
183    )

Обработчик помощи по установке WireGuard на выбранной платформе.

Arguments:
  • callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.

Отправляет сообщения с шагами помощи для установки WireGuard на выбранной платформе.

@router.callback_query(F.data.startswith('error_help_info'))
@bot_except
async def error_help(callback: aiogram.types.callback_query.CallbackQuery):
186@router.callback_query(F.data.startswith("error_help_info"))
187@bot_except
188async def error_help(callback: CallbackQuery):
189    """Обработчик помощи по устранению ошибок.
190
191    Args:
192        callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.
193
194    Отправляет сообщения с шагами помощи для устранения ошибок.
195    """
196    current_step: str = callback.data.split("_")[-1]
197
198    await post_help_book(
199        callback,
200        book=text.BOT_ERROR_STEP,
201        step=current_step,
202        start_message="📋 <b>Не волнуйтесь, вот инструкции по устранению проблем с DanVPN</b>",
203        prefix="error_help_info",
204    )

Обработчик помощи по устранению ошибок.

Arguments:
  • callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.

Отправляет сообщения с шагами помощи для устранения ошибок.

@router.message(Command('time'))
@bot_except
async def started(message: aiogram.types.message.Message, started_at):
207@router.message(Command("time"))
208@bot_except
209async def started(message: Message, started_at):
210    """Отправляет время начала работы бота.
211
212    Args:
213        message (Message): Сообщение, инициировавшее команду.
214        started_at: Время начала работы бота.
215
216    Отправляет сообщение с временем начала работы бота.
217    """
218    await message.answer(f"Время начала работы бота: {started_at}")

Отправляет время начала работы бота.

Arguments:
  • message (Message): Сообщение, инициировавшее команду.
  • started_at: Время начала работы бота.

Отправляет сообщение с временем начала работы бота.

@router.message(Command('id'))
@router.callback_query(F.data == 'user_id_info')
@bot_except
async def start_bot( trigger: Union[aiogram.types.message.Message, aiogram.types.callback_query.CallbackQuery]):
221@router.message(Command("id"))
222@router.callback_query(F.data == "user_id_info")
223@bot_except
224async def start_bot(trigger: Union[Message, CallbackQuery]):
225    """Отправляет ID пользователя.
226
227    Args:
228        trigger (Union[Message, CallbackQuery]): Сообщение или событие обратного вызова, инициировавшее команду.
229
230    Отправляет сообщение с Telegram ID пользователя.
231    """
232    await getattr(trigger, "message", trigger).answer(
233        f'Ваш Telegram ID\n\n<span class="tg-spoiler">{trigger.from_user.id}</span>'
234    )

Отправляет ID пользователя.

Arguments:
  • trigger (Union[Message, CallbackQuery]): Сообщение или событие обратного вызова, инициировавшее команду.

Отправляет сообщение с Telegram ID пользователя.

@router.message(Command('cmd'))
@router.message(Command('commands'))
@router.message(F.text == 'Команды')
@router.callback_query(F.data == 'cmd_help_info')
@bot_except
async def commands_list( trigger: Union[aiogram.types.message.Message, aiogram.types.callback_query.CallbackQuery]):
237@router.message(Command("cmd"))
238@router.message(Command("commands"))
239@router.message(F.text == "Команды")
240@router.callback_query(F.data == "cmd_help_info")
241@bot_except
242async def commands_list(trigger: Union[Message, CallbackQuery]):
243    """Отправляет список доступных команд.
244
245    Args:
246        trigger (Union[Message, CallbackQuery]): Сообщение или событие обратного вызова, инициировавшее команду.
247
248    Отправляет сообщение с перечислением доступных команд и их описанием.
249    """
250    help_t = as_list(
251        Bold("Запуск:"),
252        "/start - запуск (перезагрузка) бота",
253        Bold("Действия с аккаунтом:"),
254        as_marked_section(
255            "/account | /app - Основной функционал аккаунта",
256            "/reg - Регистрация в БД Бота",
257            "/freeze - Заморозить аккаунт",
258            "/recover - Разморозить аккаунт",
259            "/chat - Получить доступ в клиентский чат",
260            marker="~ ",
261        ),
262        Bold("Действия с конфигурациями:"),
263        as_marked_section(
264            "/me | /config - данные о моих конфигурациях wireguard",
265            "/create - создать конфигурацию",
266            marker="~ ",
267        ),
268        Bold("Действия с подпиской:"),
269        as_marked_section(
270            "/sub - Купить подписку",
271            "/refund - Сделать запрос на возврат средств",
272            "/history - История транзакций",
273            marker="~ ",
274        ),
275        Bold("Информация:"),
276        as_marked_section(
277            "/help - Помощь",
278            "/cmd - Список всех команд",
279            "/admin - функционал администратора",
280            "/bug - Доложить о баге",
281            "/id - Ваш Telegram ID",
282            "/time - время запуска бота",
283            marker="~ ",
284        ),
285        as_marked_section(
286            Bold("Расширенные возможности (тарифы от расширенного и выше):"),
287            "/server - Анализ работы сервера",
288            "/speed - Максимально доступная скорость VPN на данный момент",
289            "/mute - Отключить уведомления",
290        ),
291    )
292    await getattr(trigger, "message", trigger).answer(**help_t.as_kwargs())

Отправляет список доступных команд.

Arguments:
  • trigger (Union[Message, CallbackQuery]): Сообщение или событие обратного вызова, инициировавшее команду.

Отправляет сообщение с перечислением доступных команд и их описанием.

@router.callback_query(F.data == 'freeze_info')
@bot_except
async def freeze_config_info(callback: aiogram.types.callback_query.CallbackQuery):
295@router.callback_query(F.data == "freeze_info")
296@bot_except
297async def freeze_config_info(callback: CallbackQuery):
298    """Отправляет информацию о заморозке конфигураций.
299
300    Args:
301        callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.
302
303    Отправляет сообщение с информацией о том, как заморозить конфигурации и что делать в случае проблем.
304    """
305    await callback.message.answer(
306        "Конфигурации замораживаются, когда становятся недоступными. "
307        "\n\nПроверьте, достаточно ли средств на вашем счете? Соответствует ли количество ваших конфигураций вашему тарифу? "
308        "Возможно недавно произошли изменения в вашем тарифе, подождите несколько минут и попробуйте снова."
309        "\n\nЕсли вам все равно не понятно, почему ваша конфигурация заблокирована, воспользуйтесь командой /bug и сообщите о вашей проблеме."
310    )

Отправляет информацию о заморозке конфигураций.

Arguments:
  • callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.

Отправляет сообщение с информацией о том, как заморозить конфигурации и что делать в случае проблем.

@router.callback_query(F.data == 'freeze_account_info')
@bot_except
async def freeze_user_info(callback: aiogram.types.callback_query.CallbackQuery):
313@router.callback_query(F.data == "freeze_account_info")
314@bot_except
315async def freeze_user_info(callback: CallbackQuery):
316    """Отправляет информацию о заморозке аккаунта.
317
318    Args:
319        callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.
320
321    Отправляет сообщение с информацией о том, как заморозить аккаунт и его последствиях.
322    """
323    await callback.message.answer(
324        "Заморозка аккаунта подразумевает приостановку ежедневных списаний "
325        "и, соответственно, блокировку всех созданных конфигураций."
326        "\nРазморозить свой аккаунт можно в меню /app. После разморозки восстановление конфигураций произойдет в течение 1 минуты."
327        "\n\n<b>Стоимость услуги равна одному ежедневному списанию вашего тарифа!</b>"
328        "\n<b>Разблокировка бесплатна.</b>",
329        reply_markup=kb.freeze_user_button,
330    )

Отправляет информацию о заморозке аккаунта.

Arguments:
  • callback (CallbackQuery): Событие обратного вызова, содержащее информацию о запросе.

Отправляет сообщение с информацией о том, как заморозить аккаунт и его последствиях.

@router.message(Command('server'))
@router.callback_query(F.data == 'server_status')
@bot_except
async def server_status( trigger: Union[aiogram.types.message.Message, aiogram.types.callback_query.CallbackQuery], bot: aiogram.client.bot.Bot):
333@router.message(Command("server"))
334@router.callback_query(F.data == "server_status")
335@bot_except
336async def server_status(trigger: Union[Message, CallbackQuery], bot: Bot):
337    """Отправляет информацию о состоянии сервера.
338
339    Args:
340        trigger (Union[Message, CallbackQuery]): Сообщение или событие обратного вызова, инициировавшее команду.
341        bot (Bot): Экземпляр бота для выполнения действий.
342
343    Отправляет сообщение с текущим состоянием сервера и его загрузкой.
344    """
345    await bot.send_chat_action(trigger.from_user.id, "typing")
346
347    user_data: UserData = await find_user(trigger)
348    if not user_data:
349        return
350    elif user_data.stage < 2:
351        await getattr(trigger, "message", trigger).answer(
352            "Команда заблокирована. Выберите тариф от 'Расширенного' или выше."
353        )
354        return
355
356    try:
357        wg = WgServerTools()
358
359        server_status = await wg.get_server_status()
360        cpu_usage = await wg.get_server_cpu_usage()
361
362    except WireguardError:
363        await getattr(trigger, "message", trigger).answer(text.WG_ERROR)
364
365    else:
366        server_data = (
367            "Текущие параметры сервера:\n\n"
368            f"🖥 Сервер:        <b>{server_status.capitalize()}</b>\n\n"
369            f"🦾 СPU usage:  <b>{cpu_usage}</b>"
370        )
371
372        await getattr(trigger, "message", trigger).answer(server_data)

Отправляет информацию о состоянии сервера.

Arguments:
  • trigger (Union[Message, CallbackQuery]): Сообщение или событие обратного вызова, инициировавшее команду.
  • bot (Bot): Экземпляр бота для выполнения действий.

Отправляет сообщение с текущим состоянием сервера и его загрузкой.

@router.message(Command('speed'))
@router.callback_query(F.data == 'server_speed')
@bot_except
async def server_speed( trigger: Union[aiogram.types.message.Message, aiogram.types.callback_query.CallbackQuery], bot: aiogram.client.bot.Bot):
375@router.message(Command("speed"))
376@router.callback_query(F.data == "server_speed")
377@bot_except
378async def server_speed(trigger: Union[Message, CallbackQuery], bot: Bot):
379    """Отправляет информацию о скорости сервера.
380
381    Args:
382        trigger (Union[Message, CallbackQuery]): Сообщение или событие обратного вызова, инициировавшее команду.
383        bot (Bot): Экземпляр бота для выполнения действий.
384
385    Отправляет сообщение с текущей доступной скоростью интернет-соединения по VPN.
386    """
387    await bot.send_chat_action(trigger.from_user.id, "typing")
388
389    user_data: UserData = await find_user(trigger)
390    if not user_data:
391        return
392    elif user_data.stage < 2:
393        await getattr(trigger, "message", trigger).answer(
394            "Команда заблокирована. Выберите тариф от 'Расширенного' или выше."
395        )
396        return
397
398    try:
399        server_speed_in, server_speed_out = await test_server_speed()
400
401    except WireguardError:
402        await getattr(trigger, "message", trigger).answer(
403            text.WG_ERROR, show_alert=True
404        )
405    except DatabaseError:
406        await trigger.answer(text=text.DB_ERROR, show_alert=True)
407    except BaseBotError:
408        await trigger.answer(
409            text="Ошибка измерения пропускной способности. Попробуйте позже.",
410            show_alert=True,
411        )
412
413    else:
414        server_data = (
415            "Текущая максимально доступная скорость интернет соединения по VPN:\n\n"
416            f"📥 Скачивание:  <b>{round(server_speed_in/1048576, 2)} Мбит/с</b>\n\n"
417            f"📤 Загрузка:        <b>{round(server_speed_out/1048576, 2)} Мбит/с</b>"
418        )
419
420        await getattr(trigger, "message", trigger).answer(server_data)

Отправляет информацию о скорости сервера.

Arguments:
  • trigger (Union[Message, CallbackQuery]): Сообщение или событие обратного вызова, инициировавшее команду.
  • bot (Bot): Экземпляр бота для выполнения действий.

Отправляет сообщение с текущей доступной скоростью интернет-соединения по VPN.

@router.message(Command('chat'))
@router.message(F.text == 'Чат')
@router.callback_query(F.data == 'invite_to_chat')
@bot_except
async def get_chat_invite( trigger: Union[aiogram.types.message.Message, aiogram.types.callback_query.CallbackQuery], bot: aiogram.client.bot.Bot):
423@router.message(Command("chat"))
424@router.message(F.text == "Чат")
425@router.callback_query(F.data == "invite_to_chat")
426@bot_except
427async def get_chat_invite(trigger: Union[Message, CallbackQuery], bot: Bot):
428    """Отправляет приглашение в чат.
429
430    Args:
431        trigger (Union[Message, CallbackQuery]): Сообщение или событие обратного вызова, инициировавшее команду.
432        bot (Bot): Экземпляр бота для выполнения действий.
433
434    Отправляет сообщение с ссылкой на чат для зарегистрированных пользователей.
435    """
436    user_data = await get_user(trigger.from_user.id)
437
438    if user_data is None:
439        await getattr(trigger, "message", trigger).answer(
440            "Чат доступен только зарегистрированным пользователям. "
441            "Для начала выполните команду /reg"
442        )
443    else:
444        try:
445            link = await bot.create_chat_invite_link(
446                settings.BOT_CHAT, "chat", timedelta(hours=12), member_limit=1
447            )
448        except TelegramBadRequest:
449            logger.exception("Недоступен пользовательский чат")
450        else:
451            await getattr(trigger, "message", trigger).answer(
452                "🎉Поздравляем! Вам открыт доступ в клиентский чат.",
453                reply_markup=kb.get_chat_button(link.invite_link),
454            )

Отправляет приглашение в чат.

Arguments:
  • trigger (Union[Message, CallbackQuery]): Сообщение или событие обратного вызова, инициировавшее команду.
  • bot (Bot): Экземпляр бота для выполнения действий.

Отправляет сообщение с ссылкой на чат для зарегистрированных пользователей.