from aiogram import F, Router from aiogram.enums import ParseMode from aiogram.fsm.context import FSMContext from aiogram.fsm.state import State, StatesGroup from aiogram.types import CallbackQuery, Message from config import USERNAME_BOT from database import ( create_tracking_source, get_all_tracking_sources, get_tracking_source_stats, ) from filters.admin import IsAdminFilter from logger import logger from ..panel.keyboard import AdminPanelCallback from .keyboard import ( AdminAdsCallback, build_ads_delete_confirm_kb, build_ads_kb, build_ads_list_kb, build_ads_stats_kb, build_cancel_input_kb, ) router = Router() class AdminAdsState(StatesGroup): waiting_for_new_name = State() waiting_for_new_code = State() @router.callback_query(AdminPanelCallback.filter(F.action == "ads"), IsAdminFilter()) async def handle_ads_menu(callback_query: CallbackQuery): await callback_query.message.edit_text(text="πŸ“Š Аналитика Ρ€Π΅ΠΊΠ»Π°ΠΌΡ‹:", reply_markup=build_ads_kb()) @router.callback_query(AdminAdsCallback.filter(F.action == "create"), IsAdminFilter()) async def handle_ads_create(callback_query: CallbackQuery, state: FSMContext): await state.set_state(AdminAdsState.waiting_for_new_name) await callback_query.message.edit_text( "πŸ“ Π’Π²Π΅Π΄ΠΈΡ‚Π΅ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ Π½ΠΎΠ²ΠΎΠΉ ссылки:", reply_markup=build_cancel_input_kb() ) @router.message(AdminAdsState.waiting_for_new_name, IsAdminFilter()) async def handle_ads_name_input(message: Message, state: FSMContext): name = message.text.strip() await state.update_data(name=name) await state.set_state(AdminAdsState.waiting_for_new_code) await message.answer( f"πŸ”— Π’Π²Π΅Π΄ΠΈΡ‚Π΅ ΠΊΠΎΠ΄ ссылки для: {name}.", reply_markup=build_cancel_input_kb() ) @router.message(AdminAdsState.waiting_for_new_code, IsAdminFilter()) async def handle_ads_code_input(message: Message, state: FSMContext, session): code = message.text.strip() data = await state.get_data() name = data["name"] code_with_prefix = f"utm_{code}" try: await create_tracking_source( name=name, code=code_with_prefix, type_="utm", created_by=message.from_user.id, session=session ) stats = await get_tracking_source_stats(code_with_prefix, session) if not stats: await message.answer("❌ Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½ ΠΈΠ»ΠΈ Π½Π΅ содСрТит Π΄Π°Π½Π½Ρ‹Ρ….") return msg = format_ads_stats(stats, USERNAME_BOT) await message.answer( text=msg, reply_markup=build_ads_stats_kb(code_with_prefix), ) except Exception as e: logger.error(f"Ошибка ΠΏΡ€ΠΈ создании ссылки: {e}") await message.answer("❌ ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка ΠΏΡ€ΠΈ создании ссылки.") finally: await state.clear() @router.callback_query(AdminAdsCallback.filter(F.action == "list"), IsAdminFilter()) async def handle_ads_list(callback_query: CallbackQuery, session): try: ads = await get_all_tracking_sources(session) reply_markup = build_ads_list_kb(ads, current_page=1, total_pages=1) await callback_query.message.edit_text( "πŸ“‹ Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ ссылку для просмотра статистики:", reply_markup=reply_markup ) except Exception as e: logger.error(f"Ошибка ΠΏΡ€ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠΈ списка UTM: {e}") await callback_query.message.edit_text("ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка ΠΏΡ€ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠΈ списка.") @router.callback_query(AdminAdsCallback.filter(F.action == "view"), IsAdminFilter()) async def handle_ads_view(callback_query: CallbackQuery, callback_data: AdminAdsCallback, session): code = callback_data.code try: stats = await get_tracking_source_stats(code, session) if not stats: await callback_query.message.edit_text("❌ Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½ ΠΈΠ»ΠΈ Π½Π΅ содСрТит Π΄Π°Π½Π½Ρ‹Ρ….") return msg = format_ads_stats(stats, USERNAME_BOT) await callback_query.message.edit_text( text=msg, reply_markup=build_ads_stats_kb(code), parse_mode=ParseMode.HTML ) except Exception as e: logger.error(f"Ошибка ΠΏΡ€ΠΈ просмотрС статистики: {e}") await callback_query.message.edit_text("❌ Ошибка ΠΏΡ€ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠΈ статистики.") @router.callback_query(AdminAdsCallback.filter(F.action == "delete_confirm"), IsAdminFilter()) async def handle_ads_delete_confirm(callback_query: CallbackQuery, callback_data: AdminAdsCallback): code = callback_data.code await callback_query.message.edit_text( text=f"Π’Ρ‹ ΡƒΠ²Π΅Ρ€Π΅Π½Ρ‹, Ρ‡Ρ‚ΠΎ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ ссылку {code}?", reply_markup=build_ads_delete_confirm_kb(code), ) @router.callback_query(AdminAdsCallback.filter(F.action == "delete"), IsAdminFilter()) async def handle_ads_delete(callback_query: CallbackQuery, callback_data: AdminAdsCallback, session): code = callback_data.code try: await session.execute("UPDATE users SET source_code = NULL WHERE source_code = $1", code) await session.execute("DELETE FROM tracking_sources WHERE code = $1", code) await callback_query.message.edit_text(f"πŸ—‘οΈ Бсылка {code} ΡƒΠ΄Π°Π»Π΅Π½Π°.", reply_markup=build_ads_kb()) except Exception as e: logger.error(f"Ошибка ΠΏΡ€ΠΈ ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠΈ ΠΌΠ΅Ρ‚ΠΊΠΈ {code}: {e}", exc_info=True) await callback_query.message.edit_text("❌ НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ ссылку.") def format_ads_stats(stats: dict, username_bot: str) -> str: return ( f"πŸ“Š Бтатистика ΠΏΠΎ Ρ€Π΅ΠΊΠ»Π°ΠΌΠ½ΠΎΠΉ ссылкС\n\n" f"πŸ“Œ НазваниС: {stats['name']}\n" f"πŸ”— Бсылка: https://t.me/{username_bot}?start={stats['code']}\n" f"πŸ•“ Π‘ΠΎΠ·Π΄Π°Π½Π°: {stats['created_at'].strftime('%d.%m.%Y %H:%M')}\n\n" f"πŸ’‘ ΠΠΊΡ‚ΠΈΠ²Π½ΠΎΡΡ‚ΡŒ:\n" f"β”” πŸ†• РСгистраций: {stats.get('registrations', 0)}\n" f"β”” πŸ§ͺ Π’Ρ€ΠΈΠ°Π»ΠΎΠ²: {stats.get('trials', 0)}\n" f"\nπŸ’° Ѐинансовая информация:\n" f"β”” πŸ’³ ΠŸΠΎΠΊΡƒΠΏΠΎΠΊ: {stats.get('payments', 0)}\n\n" f"ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€ статистики ΠΈ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ Ρ€Π΅ΠΊΠ»Π°ΠΌΠ½Ρ‹ΠΌΠΈ ссылками." ) @router.callback_query(AdminAdsCallback.filter(F.action == "cancel_input"), IsAdminFilter()) async def handle_ads_cancel_input(callback_query: CallbackQuery, state: FSMContext): await state.clear() await callback_query.message.edit_text(text="πŸ“Š Аналитика Ρ€Π΅ΠΊΠ»Π°ΠΌΡ‹:", reply_markup=build_ads_kb())