"""Handlers for admin review/contact groups.""" import logging from aiogram import F, Router, types from aiogram.filters import Command import bot_state as state_store from config import ( BOT_USERNAME, CHAT_CONTACT_ADMIN_GROUP_ID, CHATROOM_PRIVATE_BACKUP_GROUP_ID, CHATROOM_SEMIPUBLIC_GROUP_ID, MAIN_PUBLIC_CHANNEL_ID, REVIEW_ADMIN_CHATROOM_SEMIPUBLIC_GROUP_ID, ) from hashing import register_file from keyboards import publish_kb from utils import build_quote, get_admin_display_name, send_media_items logger = logging.getLogger(__name__) router = Router(name="admin") # ── Submission approve / reject ─────────────────────────────────────────────── @router.callback_query(F.data.startswith("a|")) async def approve(cb: types.CallbackQuery): sub_id = int(cb.data.split("|")[1]) if sub_id not in state_store.submissions: await cb.answer("Submission not found.", show_alert=True) return await cb.message.edit_reply_markup(reply_markup=publish_kb(sub_id)) await cb.answer() @router.callback_query(F.data.startswith("p|")) async def publish(cb: types.CallbackQuery): parts = cb.data.split("|") target = parts[1] sub_id = int(parts[2]) submission = state_store.submissions.get(sub_id) if not submission: await cb.answer("Submission not found.", show_alert=True) return user_id = submission["user_id"] media = submission["media"] duplicate_media = [m for m in media if m.get("file_unique_id", "") in state_store.backup_hashes] unique_media = [m for m in media if m.get("file_unique_id", "") not in state_store.backup_hashes] if duplicate_media: try: user_info = await cb.bot.get_chat(user_id) user_ref = ( f'@{user_info.username}' if getattr(user_info, "username", None) else str(user_id) ) except Exception: user_ref = str(user_id) try: await cb.bot.send_message( REVIEW_ADMIN_CHATROOM_SEMIPUBLIC_GROUP_ID, f"⚠️ Content from {user_ref} contains {len(duplicate_media)} duplicate(s). " "Skipping those.", parse_mode="HTML", ) except Exception: logger.warning("Could not send duplicate notice") caption = ( "This is an anonymous submission reviewed by admins.\n\n" "You can apply having self-harm imagery posted using " f'this bot.' ) if unique_media: await send_media_items(cb.bot, CHATROOM_PRIVATE_BACKUP_GROUP_ID, unique_media) for item in unique_media: register_file(item["file_unique_id"]) if target in {"d", "both"}: await send_media_items(cb.bot, CHATROOM_SEMIPUBLIC_GROUP_ID, unique_media, caption=caption) if target in {"b", "both"}: await send_media_items(cb.bot, MAIN_PUBLIC_CHANNEL_ID, unique_media, caption=caption) try: await cb.bot.send_message(user_id, "Your submission was approved ✅") except Exception: logger.warning("Could not notify user %s of approval", user_id) state_store.submissions.pop(sub_id, None) try: await cb.message.edit_reply_markup() except Exception: pass await cb.answer() @router.callback_query(F.data.startswith("r|")) async def reject(cb: types.CallbackQuery): sub_id = int(cb.data.split("|")[1]) submission = state_store.submissions.get(sub_id) if not submission: await cb.answer("Submission not found.", show_alert=True) return try: await cb.bot.send_message(submission["user_id"], "Your submission was rejected ❌") except Exception: logger.warning("Could not notify user %s of rejection", submission["user_id"]) state_store.submissions.pop(sub_id, None) try: await cb.message.edit_reply_markup() except Exception: pass await cb.answer() # ── Admin contact-group reply commands ──────────────────────────────────────── @router.message(F.chat.id == CHAT_CONTACT_ADMIN_GROUP_ID, F.reply_to_message, Command("stop")) async def admin_stop_chat(message: types.Message): route = state_store.chat_message_map.get(message.reply_to_message.message_id) if not route: return user_id = route["user_id"] if state_store.chat_sessions.pop(user_id, None): try: await message.bot.send_message(user_id, "An admin has closed this chat.") except Exception: pass @router.message(F.chat.id == CHAT_CONTACT_ADMIN_GROUP_ID, F.reply_to_message, Command("ban")) async def admin_ban_user(message: types.Message): route = state_store.chat_message_map.get(message.reply_to_message.message_id) if not route: return user_id = route["user_id"] state_store.banned_chat_users.add(user_id) if state_store.chat_sessions.pop(user_id, None): try: await message.bot.send_message(user_id, "An admin has closed this chat.") except Exception: pass @router.message(F.chat.id == CHAT_CONTACT_ADMIN_GROUP_ID, F.reply_to_message, Command("private")) async def admin_private_chat(message: types.Message): route = state_store.chat_message_map.get(message.reply_to_message.message_id) if not route: return user_id = route["user_id"] username = ( f"@{message.from_user.username}" if message.from_user.username else message.from_user.full_name ) try: await message.bot.send_message( user_id, f"An admin wants to continue this chat privately. Feel free to text them at {username}, " "or open a new chat here. This chat is now closed.", ) except Exception: pass state_store.chat_sessions.pop(user_id, None) @router.message(F.chat.id == CHAT_CONTACT_ADMIN_GROUP_ID, F.reply_to_message) async def admin_reply(message: types.Message): if message.text in {"/stop", "/ban", "/private"}: return route = state_store.chat_message_map.get(message.reply_to_message.message_id) if not route: return user_id = route["user_id"] if user_id not in state_store.chat_sessions: return quote = build_quote(route["quote"]) admin_name = get_admin_display_name(message.from_user) try: if message.text: await message.bot.send_message(user_id, f"{admin_name}\n{quote}\n\n{message.text}") else: await message.bot.send_message(user_id, f"{admin_name}\n{quote}") await message.bot.copy_message( user_id, CHAT_CONTACT_ADMIN_GROUP_ID, message.message_id ) except Exception: logger.exception("Failed to relay admin reply to user %s", user_id)