From bcd7a5d59d48a23b7b6459208e15c2f75738cd76 Mon Sep 17 00:00:00 2001 From: hteppl Date: Wed, 15 Jan 2025 07:58:46 +0300 Subject: [PATCH] Implement banned by users handler --- handlers/admin/__init__.py | 2 + handlers/admin/admin_bans.py | 107 +++++++++++++++++++++++++++++++++++ keyboards/admin/bans_kb.py | 21 +++++++ 3 files changed, 130 insertions(+) create mode 100644 handlers/admin/admin_bans.py create mode 100644 keyboards/admin/bans_kb.py diff --git a/handlers/admin/__init__.py b/handlers/admin/__init__.py index 1dffebf9..cb91e6f3 100644 --- a/handlers/admin/__init__.py +++ b/handlers/admin/__init__.py @@ -3,6 +3,7 @@ __all__ = ("router",) from aiogram import Router from .admin_backups import router as backups_router +from .admin_bans import router as bans_router from .admin_coupons import router as coupons_router from .admin_panel import router as panel_router from .admin_restart import router as restart_router @@ -22,4 +23,5 @@ router.include_routers( sender_router, coupons_router, restart_router, + bans_router, ) diff --git a/handlers/admin/admin_bans.py b/handlers/admin/admin_bans.py new file mode 100644 index 00000000..a515a14e --- /dev/null +++ b/handlers/admin/admin_bans.py @@ -0,0 +1,107 @@ +from typing import Any + +from aiogram import F, Router +from aiogram.types import CallbackQuery, BufferedInputFile + +from database import delete_user_data +from filters.admin import IsAdminFilter +from keyboards.admin.bans_kb import build_bans_kb +from keyboards.admin.panel_kb import AdminPanelCallback, build_admin_back_kb + +router = Router() + + +@router.callback_query( + AdminPanelCallback.filter(F.action == "bans"), + IsAdminFilter(), +) +async def handle_bans( + callback_query: CallbackQuery +): + text = ( + "🚫 Заблокировавшие бота" + "\n\nЗдесь можно просматривать и удалять пользователей, которые забанили вашего бота!" + ) + + await callback_query.message.edit_text( + text=text, + reply_markup=build_bans_kb(), + ) + + +@router.callback_query( + AdminPanelCallback.filter(F.action == "bans_export"), + IsAdminFilter(), +) +async def handle_bans_export( + callback_query: CallbackQuery, + session: Any +): + kb = build_admin_back_kb("management") + + try: + banned_users = await session.fetch("SELECT tg_id, blocked_at FROM blocked_users") + + import csv + import io + + csv_output = io.StringIO() + writer = csv.writer(csv_output) + writer.writerow(["tg_id", "blocked_at"]) + for user in banned_users: + writer.writerow([user["tg_id"], user["blocked_at"]]) + + csv_output.seek(0) + + document = BufferedInputFile( + file=csv_output.getvalue().encode("utf-8"), filename="banned_users.csv" + ) + + await callback_query.message.answer_document( + document=document, + caption="📥 Экспорт пользователей, заблокировавших бота в CSV", + ) + except Exception as e: + await callback_query.message.answer( + text=f"❗ Произошла ошибка при экспорте: {e}", + reply_markup=kb, + ) + + +@router.callback_query( + AdminPanelCallback.filter(F.action == "bans_delete_banned"), + IsAdminFilter(), +) +async def handle_bans_delete_banned( + callback_query: CallbackQuery, + session: Any +): + kb = build_admin_back_kb("bans") + + try: + blocked_users = await session.fetch("SELECT tg_id FROM blocked_users") + blocked_ids = [record["tg_id"] for record in blocked_users] + + if not blocked_ids: + await callback_query.message.answer( + text="📂 Нет заблокировавших пользователей для удаления.", + reply_markup=kb, + ) + return + + for tg_id in blocked_ids: + await delete_user_data(session, tg_id) + + await session.execute( + "DELETE FROM blocked_users WHERE tg_id = ANY($1)", blocked_ids + ) + + await callback_query.message.answer( + text=f"🗑️ Удалены данные о {len(blocked_ids)} пользователях и связанных записях.", + reply_markup=kb, + ) + except Exception as e: + await callback_query.message.answer( + text=f"❗ Произошла ошибка при удалении записей: {e}", + reply_markup=kb, + ) diff --git a/keyboards/admin/bans_kb.py b/keyboards/admin/bans_kb.py new file mode 100644 index 00000000..958d0a14 --- /dev/null +++ b/keyboards/admin/bans_kb.py @@ -0,0 +1,21 @@ +from aiogram.types import InlineKeyboardMarkup +from aiogram.utils.keyboard import InlineKeyboardBuilder + +from keyboards.admin.panel_kb import build_admin_back_btn, AdminPanelCallback + + +def build_bans_kb() -> InlineKeyboardMarkup: + builder = InlineKeyboardBuilder() + builder.button( + text="📄 Выгрузить в CSV", + callback_data=AdminPanelCallback(action="bans_export").pack() + ) + builder.button( + text="🗑️ Удалить из БД", + callback_data=AdminPanelCallback(action="bans_delete_banned").pack() + ) + builder.row( + build_admin_back_btn("management") + ) + builder.adjust(1) + return builder.as_markup()