From 44d6fe87ddfdba1fabdbf57725b381b52fc03802 Mon Sep 17 00:00:00 2001 From: Vladless Date: Sun, 17 Aug 2025 22:50:46 +0300 Subject: [PATCH] minor fixes: utm_api/donations and module payments/users info in admin --- database/models.py | 11 ++++-- handlers/admin/users/users_handler.py | 48 ++++++++++++++++++--------- handlers/coupons.py | 2 +- handlers/pay.py | 13 ++++++-- 4 files changed, 52 insertions(+), 22 deletions(-) diff --git a/database/models.py b/database/models.py index d7d7da96..4871939c 100644 --- a/database/models.py +++ b/database/models.py @@ -43,7 +43,14 @@ class User(DictLikeMixin, Base): is_bot = Column(Boolean, default=False) balance = Column(Float, default=0.0) trial = Column(Integer, default=0) - source_code = Column(String, ForeignKey("tracking_sources.code")) + source_code = Column( + String, + ForeignKey( + "tracking_sources.code", + ondelete="SET NULL", + onupdate="CASCADE", + ), + nullable=True, ) created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow) @@ -125,7 +132,7 @@ class CouponUsage(DictLikeMixin, Base): coupon_id = Column( Integer, - ForeignKey("coupons.id", ondelete="CASCADE"), # Каскадное удаление + ForeignKey("coupons.id", ondelete="CASCADE"), primary_key=True ) user_id = Column(BigInteger, primary_key=True) diff --git a/handlers/admin/users/users_handler.py b/handlers/admin/users/users_handler.py index 44bea5e3..10426327 100644 --- a/handlers/admin/users/users_handler.py +++ b/handlers/admin/users/users_handler.py @@ -10,6 +10,7 @@ from aiogram import F, Router, types from aiogram.exceptions import TelegramBadRequest from aiogram.fsm.context import FSMContext from aiogram.fsm.state import State, StatesGroup +from aiogram.utils.formatting import Text, Bold, BlockQuote from aiogram.types import CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup, Message from aiogram.utils.keyboard import InlineKeyboardBuilder from sqlalchemy import delete, func, or_, select, update @@ -1155,15 +1156,15 @@ async def process_user_search( result_ref_by = await session.execute(stmt_ref_by) referrer_tg_id = result_ref_by.scalar_one_or_none() - referrer_text = "" + referrer_text = None if referrer_tg_id: stmt_referrer = select(User.username).where(User.tg_id == referrer_tg_id) result_referrer = await session.execute(stmt_referrer) ref_username = result_referrer.scalar_one_or_none() if ref_username: - referrer_text = f"\n🤝 Пригласил: @{ref_username}" + referrer_text = f"🤝 Пригласил: @{ref_username}" else: - referrer_text = f"\n🤝 Пригласил: {referrer_tg_id}" + referrer_text = f"🤝 Пригласил: {referrer_tg_id}" stmt = select(func.count(Payment.id), func.coalesce(func.sum(Payment.amount), 0)).where( Payment.status == "success", Payment.tg_id == tg_id @@ -1185,28 +1186,43 @@ async def process_user_search( user_obj = await session.get(User, tg_id) full_name = user_obj.first_name if user_obj else None - text = ( - f"📊 Информация о пользователе\n\n" - f"
" - f"🆔 ID: {tg_id}\n" - f"📄 Логин: @{username}{f' ({full_name})' if full_name else ''}\n" - f"📅 Дата регистрации: {created_at_str}\n" - f"🏃 Дата активности: {updated_at_str}\n" - f"💰 Баланс: {balance} Р.\n" - f"💳 Пополнения: {topups_sum} Р. ({topups_amount} шт.)\n" - f"👥 Количество рефералов: {referral_count}{referrer_text}" - f"
" + body = Text( + f"🆔 ID: {tg_id}\n", + f"📄 Логин: @{username}" if username else "📄 Логин: —", + f"{f' ({full_name})' if full_name else ''}\n", + f"📅 Дата регистрации: {created_at_str}\n", + f"🏃 Дата активности: {updated_at_str}\n", + f"💰 Баланс: {balance} Р.\n", + f"💳 Пополнения: {topups_sum} Р. ({topups_amount} шт.)\n", + f"👥 Количество рефералов: {referral_count}\n", ) + if referrer_text: + body += Text(referrer_text, "\n") + + text_builder = Text( + Bold("📊 Информация о пользователе"), "\n\n", + BlockQuote(body) + ) + + text = text_builder.as_html() kb = build_user_edit_kb(tg_id, key_records, is_banned=is_banned) if edit: try: - await message.edit_text(text=text, reply_markup=kb) + await message.edit_text( + text=text, + reply_markup=kb, + disable_web_page_preview=True + ) except TelegramBadRequest: pass else: - await message.answer(text=text, reply_markup=kb) + await message.answer( + text=text, + reply_markup=kb, + disable_web_page_preview=True + ) async def change_expiry_time(expiry_time: int, email: str, session: AsyncSession) -> Exception | None: diff --git a/handlers/coupons.py b/handlers/coupons.py index b07b4f10..380a575f 100644 --- a/handlers/coupons.py +++ b/handlers/coupons.py @@ -69,7 +69,7 @@ async def handle_activate_coupon(callback_query_or_message: Message | CallbackQu await state.set_state(CouponActivationState.waiting_for_coupon_code) -@router.message(CouponActivationState.waiting_for_coupon_code) +@router.message(CouponActivationState.waiting_for_coupon_code, F.text) async def process_coupon_code(message: Message, state: FSMContext, session: Any): coupon_code = message.text.strip() await activate_coupon(message, state, session, coupon_code=coupon_code) diff --git a/handlers/pay.py b/handlers/pay.py index 3f7828e2..0f2487f6 100644 --- a/handlers/pay.py +++ b/handlers/pay.py @@ -88,10 +88,18 @@ async def handle_pay(callback_query: CallbackQuery, state: FSMContext, session: payment_handlers.append(process_callback_pay_robokassa) if FREEKASSA_ENABLE: payment_handlers.append(process_callback_pay_freekassa) - if TRIBUTE_ENABLE: + if TRIBUTE_ENABLE: payment_handlers.append(process_callback_pay_tribute) - if len(payment_handlers) == 1: + module_buttons = await run_hooks( + "pay_menu_buttons", + chat_id=callback_query.from_user.id, + admin=False, + session=session + ) + has_extra_menu_items = bool(module_buttons) or bool(DONATIONS_ENABLE) or bool(TRIBUTE_ENABLE) + + if len(payment_handlers) == 1 and not has_extra_menu_items: return await payment_handlers[0](callback_query, state, session) builder = InlineKeyboardBuilder() @@ -124,7 +132,6 @@ async def handle_pay(callback_query: CallbackQuery, state: FSMContext, session: if DONATIONS_ENABLE: builder.row(InlineKeyboardButton(text="💰 Поддержать проект", callback_data="donate")) - module_buttons = await run_hooks("pay_menu_buttons", chat_id=callback_query.from_user.id, admin=False, session=session) builder = insert_hook_buttons(builder, module_buttons) builder.row(InlineKeyboardButton(text=MAIN_MENU, callback_data="profile"))