generated from FOSS/Bot-Template
182 lines
7.6 KiB
Python
182 lines
7.6 KiB
Python
# - *- coding: utf- 8 - *-
|
||
import html as _html
|
||
|
||
from aiogram import F, Router
|
||
from aiogram.filters import Command
|
||
from aiogram.fsm.state import State, StatesGroup
|
||
from aiogram.types import CallbackQuery, Message
|
||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||
|
||
from tgbot.database.db_settings import SettingsRepository
|
||
from tgbot.utils.const_functions import ikb, _interval_label, _interval_kb, _show_panel
|
||
from tgbot.utils.misc.bot_models import FSM
|
||
|
||
router = Router(name=__name__)
|
||
|
||
ALLOWED_INTERVALS = (0, 5, 12, 24)
|
||
|
||
|
||
# ─── FSM ────────────────────────────────────────────────────────────────────
|
||
|
||
|
||
class AdminStates(StatesGroup):
|
||
wait_message = State() # ждём новое приветственное сообщение
|
||
wait_btn_text = State() # ждём текст inline-кнопки
|
||
wait_btn_link = State() # ждём ссылку inline-кнопки
|
||
|
||
|
||
# ─── Команда /admin ──────────────────────────────────────────────────────────
|
||
|
||
|
||
@router.message(Command("admin"))
|
||
async def cmd_admin(message: Message, state: FSM, **_) -> None:
|
||
await state.clear()
|
||
await _show_panel(message)
|
||
|
||
|
||
# ─── Главное меню (возврат из подменю) ───────────────────────────────────────
|
||
|
||
|
||
@router.callback_query(F.data == "adm:main")
|
||
async def adm_main(call: CallbackQuery, state: FSM, **_) -> None:
|
||
await state.clear()
|
||
await _show_panel(call)
|
||
|
||
|
||
# ─── Включить / выключить бота ───────────────────────────────────────────────
|
||
|
||
|
||
@router.callback_query(F.data == "adm:toggle")
|
||
async def adm_toggle(call: CallbackQuery, **_) -> None:
|
||
repo = SettingsRepository()
|
||
settings = await repo.get()
|
||
await repo.update(status_work=not settings.status_work)
|
||
await _show_panel(call)
|
||
|
||
|
||
# ─── Изменение приветственного сообщения ─────────────────────────────────────
|
||
|
||
|
||
@router.callback_query(F.data == "adm:set_msg")
|
||
async def adm_set_msg(call: CallbackQuery, state: FSM, **_) -> None:
|
||
await state.set_state(AdminStates.wait_message)
|
||
kb = InlineKeyboardBuilder()
|
||
kb.row(ikb("◀ Отмена", data="adm:cancel"))
|
||
await call.message.edit_text(
|
||
"📝 <b>Отправьте новое приветственное сообщение</b>\n\n"
|
||
"• Просто текст <b>или</b> фото с подписью (caption)\n"
|
||
"• HTML-разметка поддерживается\n\n"
|
||
"Чтобы отменить — нажмите кнопку ниже.",
|
||
reply_markup=kb.as_markup(),
|
||
)
|
||
await call.answer()
|
||
|
||
|
||
@router.message(AdminStates.wait_message)
|
||
async def adm_recv_message(message: Message, state: FSM, **_) -> None:
|
||
repo = SettingsRepository()
|
||
if message.photo:
|
||
await repo.update(
|
||
misc_message=message.caption or "",
|
||
misc_message_media=message.photo[-1].file_id,
|
||
)
|
||
elif message.text:
|
||
await repo.update(misc_message=message.text, misc_message_media=None)
|
||
else:
|
||
await message.answer("❌ Поддерживаются только текст и фото с подписью")
|
||
return
|
||
await state.clear()
|
||
settings = await repo.get()
|
||
await message.answer("✅ Сообщение сохранено")
|
||
await _show_panel(message, settings)
|
||
|
||
|
||
# ─── Интервал напоминаний ─────────────────────────────────────────────────────
|
||
|
||
|
||
@router.callback_query(F.data == "adm:interval")
|
||
async def adm_interval_menu(call: CallbackQuery, **_) -> None:
|
||
settings = await SettingsRepository().get()
|
||
await call.message.edit_text(
|
||
"🔔 <b>Интервал напоминаний</b>\n\n"
|
||
"Бот повторно отправит сообщение через выбранный промежуток.\n"
|
||
"<b>Выкл</b> — напоминания не отправляются.",
|
||
reply_markup=_interval_kb(settings.remind_interval),
|
||
)
|
||
await call.answer()
|
||
|
||
|
||
@router.callback_query(F.data.startswith("adm:int:"))
|
||
async def adm_set_interval(call: CallbackQuery, **_) -> None:
|
||
try:
|
||
hours = int(call.data.split(":")[2])
|
||
except (IndexError, ValueError):
|
||
await call.answer("Неверное значение", show_alert=True)
|
||
return
|
||
if hours not in ALLOWED_INTERVALS:
|
||
await call.answer("Неверное значение", show_alert=True)
|
||
return
|
||
await SettingsRepository().update(remind_interval=hours)
|
||
await call.answer(f"✅ Интервал: {_interval_label(hours)}")
|
||
await _show_panel(call)
|
||
|
||
|
||
# ─── Кнопка в приветственном сообщении ───────────────────────────────────────
|
||
|
||
|
||
@router.callback_query(F.data == "adm:set_btn")
|
||
async def adm_set_btn(call: CallbackQuery, state: FSM, **_) -> None:
|
||
await state.set_state(AdminStates.wait_btn_text)
|
||
kb = InlineKeyboardBuilder()
|
||
kb.row(ikb("◀ Отмена", data="adm:cancel"))
|
||
await call.message.edit_text(
|
||
"🔗 <b>Введите текст кнопки</b>\n\nНапример: <code>Перейти на сайт</code>",
|
||
reply_markup=kb.as_markup(),
|
||
)
|
||
await call.answer()
|
||
|
||
|
||
@router.message(AdminStates.wait_btn_text, F.text)
|
||
async def adm_recv_btn_text(message: Message, state: FSM, **_) -> None:
|
||
await state.update_data(btn_text=message.text.strip())
|
||
await state.set_state(AdminStates.wait_btn_link)
|
||
await message.answer(
|
||
"🔗 <b>Теперь введите ссылку для кнопки</b>\n\n"
|
||
"Например: <code>https://example.com</code>"
|
||
)
|
||
|
||
|
||
@router.message(AdminStates.wait_btn_link, F.text)
|
||
async def adm_recv_btn_link(message: Message, state: FSM, **_) -> None:
|
||
data = await state.get_data()
|
||
btn_text = data.get("btn_text", "")
|
||
btn_link = message.text.strip()
|
||
if not btn_link.startswith(("http://", "https://", "tg://")):
|
||
await message.answer(
|
||
"❌ Ссылка должна начинаться с <code>http://</code>, "
|
||
"<code>https://</code> или <code>tg://</code>"
|
||
)
|
||
return
|
||
repo = SettingsRepository()
|
||
await repo.update(misc_finl_text=btn_text, misc_finl_link=btn_link)
|
||
await state.clear()
|
||
settings = await repo.get()
|
||
await message.answer("✅ Кнопка сохранена")
|
||
await _show_panel(message, settings)
|
||
|
||
|
||
@router.callback_query(F.data == "adm:clr_btn")
|
||
async def adm_clr_btn(call: CallbackQuery, **_) -> None:
|
||
await SettingsRepository().update(misc_finl_text=None, misc_finl_link=None)
|
||
await call.answer("🗑 Кнопка удалена")
|
||
await _show_panel(call)
|
||
|
||
|
||
# ─── Отмена текущего действия ─────────────────────────────────────────────────
|
||
|
||
|
||
@router.callback_query(F.data == "adm:cancel")
|
||
async def adm_cancel(call: CallbackQuery, state: FSM, **_) -> None:
|
||
await state.clear()
|
||
await _show_panel(call)
|