First commit

This commit is contained in:
2026-01-23 04:45:55 +07:00
commit 0b251c5967
118 changed files with 9580 additions and 0 deletions

View File

@@ -0,0 +1,117 @@
from typing import Dict, Tuple
from aiogram import Router, F
from aiogram.filters import Command
from aiogram.types import Message, CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup
from aiogram.fsm.context import FSMContext
from bot.utils import status_clear
# -------------------
# Router
# -------------------
router: Router = Router(name="anon_router")
# -------------------
# Конфигурация
# -------------------
# CHAT_ID в формате "-100000_29" -> chat_id + thread_id
CHAT_ID: str = "-1003098225669_724"
def parse_chat_id(chat_id_str: str) -> Tuple[int, int]:
chat_str, thread_str = chat_id_str.split("_")
return int(chat_str), int(thread_str)
ADMIN_CHAT_ID, ADMIN_THREAD_ID = parse_chat_id(CHAT_ID)
# -------------------
# FSM состояния
# -------------------
class AnonStates:
USER_WAITING_TEXT = "user_waiting_text"
ADMIN_WAITING_REPLY = "admin_waiting_reply"
# -------------------
# Словари для отслеживания сообщений
# -------------------
# user_id -> message_id в админском топике
user_to_admin_map: Dict[int, int] = {}
# admin_message_id -> user_id
admin_to_user_map: Dict[int, int] = {}
# -------------------
# Команда /anon или callback
# -------------------
@router.callback_query(F.data.casefold() == "anon")
@router.message(Command("anon"))
async def anon_start(message: Message | CallbackQuery, state: FSMContext) -> None:
"""Начало анонимного сообщения. Ждём текст пользователя."""
await status_clear(message=message, state=state)
await state.clear()
await state.set_state(AnonStates.USER_WAITING_TEXT)
text = "Напишите сообщение, которое вы хотите отправить анонимно администраторам."
if isinstance(message, Message):
await message.reply(text)
else:
await message.message.answer(text)
# -------------------
# Получение текста от пользователя
# -------------------
@router.message(F.text, F.state == AnonStates.USER_WAITING_TEXT)
async def anon_send_text(message: Message, state: FSMContext) -> None:
"""Пересылает текст пользователя в админский топик анонимно."""
anon_text = message.text.strip()
if not anon_text:
await message.reply("Сообщение не может быть пустым. Попробуйте снова.")
return
forwarded_text = f"Сообщение от [пользователя](tg://user?id={message.from_user.id}):\n{anon_text}"
keyboard = InlineKeyboardMarkup(
inline_keyboard=[
[InlineKeyboardButton(text="Ответить", callback_data=f"anon_reply:{message.from_user.id}")]
]
)
sent_msg = await message.bot.send_message(
chat_id=ADMIN_CHAT_ID,
message_thread_id=ADMIN_THREAD_ID,
text=forwarded_text,
parse_mode="Markdown",
reply_markup=keyboard
)
user_to_admin_map[message.from_user.id] = sent_msg.message_id
admin_to_user_map[sent_msg.message_id] = message.from_user.id
await message.reply("Ваше сообщение отправлено анонимно администраторам.")
await state.clear()
# -------------------
# Кнопка "Ответить" админа
# -------------------
@router.callback_query(F.data.startswith("anon_reply:"))
async def anon_admin_reply(callback: CallbackQuery, state: FSMContext) -> None:
"""Начинаем сессию ответа админа пользователю."""
user_id = int(callback.data.split(":")[1])
await state.set_state(AnonStates.ADMIN_WAITING_REPLY)
await state.update_data(reply_to_user=user_id)
await callback.message.answer(f"Введите ответ для пользователя [id={user_id}]:")
await callback.answer()
# -------------------
# Текст ответа админа
# -------------------
@router.message(F.text, F.state == AnonStates.ADMIN_WAITING_REPLY)
async def anon_send_admin_text(message: Message, state: FSMContext) -> None:
"""Пересылает текст админа пользователю."""
data = await state.get_data()
reply_to_user = data.get("reply_to_user")
if reply_to_user:
await message.bot.send_message(
chat_id=reply_to_user,
text=f"Ответ администратора:\n{message.text}"
)
await message.reply("Сообщение отправлено пользователю.")
await state.clear()