Files

182 lines
7.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# - *- 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)