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())