forked from HSE_team/BetterCallPraskovia
доработка
This commit is contained in:
parent
56489de4f2
commit
af78fc633f
@ -3,6 +3,8 @@ pydantic-settings>=2.1.0
|
|||||||
python-dotenv>=1.0.0
|
python-dotenv>=1.0.0
|
||||||
aiogram>=3.10.0
|
aiogram>=3.10.0
|
||||||
sqlalchemy>=2.0.0
|
sqlalchemy>=2.0.0
|
||||||
|
aiosqlite>=0.19.0
|
||||||
|
httpx>=0.25.0
|
||||||
yookassa>=2.4.0
|
yookassa>=2.4.0
|
||||||
fastapi>=0.104.0
|
fastapi>=0.104.0
|
||||||
uvicorn>=0.24.0
|
uvicorn>=0.24.0
|
||||||
|
|||||||
@ -1,29 +1,67 @@
|
|||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
from sqlalchemy import select
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
from typing import Optional
|
||||||
from tg_bot.infrastructure.database.models import UserModel
|
from tg_bot.infrastructure.database.models import UserModel
|
||||||
|
|
||||||
|
|
||||||
class UserService:
|
class UserService:
|
||||||
|
|
||||||
def __init__(self, session: Session):
|
def __init__(self, session: AsyncSession):
|
||||||
self.session = session
|
self.session = session
|
||||||
|
|
||||||
|
async def get_user_by_telegram_id(self, telegram_id: int) -> Optional[UserModel]:
|
||||||
|
result = await self.session.execute(
|
||||||
|
select(UserModel).filter_by(telegram_id=str(telegram_id))
|
||||||
|
)
|
||||||
|
return result.scalar_one_or_none()
|
||||||
|
|
||||||
|
async def get_or_create_user(
|
||||||
|
self,
|
||||||
|
telegram_id: int,
|
||||||
|
username: str = "",
|
||||||
|
first_name: str = "",
|
||||||
|
last_name: str = ""
|
||||||
|
) -> UserModel:
|
||||||
|
user = await self.get_user_by_telegram_id(telegram_id)
|
||||||
|
if not user:
|
||||||
|
user = UserModel(
|
||||||
|
telegram_id=str(telegram_id),
|
||||||
|
username=username,
|
||||||
|
first_name=first_name,
|
||||||
|
last_name=last_name
|
||||||
|
)
|
||||||
|
self.session.add(user)
|
||||||
|
await self.session.commit()
|
||||||
|
else:
|
||||||
|
user.username = username
|
||||||
|
user.first_name = first_name
|
||||||
|
user.last_name = last_name
|
||||||
|
await self.session.commit()
|
||||||
|
return user
|
||||||
|
|
||||||
|
async def update_user_questions(self, telegram_id: int) -> bool:
|
||||||
|
user = await self.get_user_by_telegram_id(telegram_id)
|
||||||
|
if user:
|
||||||
|
user.questions_used += 1
|
||||||
|
await self.session.commit()
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
async def activate_premium(self, telegram_id: int) -> bool:
|
async def activate_premium(self, telegram_id: int) -> bool:
|
||||||
try:
|
try:
|
||||||
user = self.session.query(UserModel) \
|
user = await self.get_user_by_telegram_id(telegram_id)
|
||||||
.filter(UserModel.telegram_id == str(telegram_id)) \
|
|
||||||
.first()
|
|
||||||
if user:
|
if user:
|
||||||
user.is_premium = True
|
user.is_premium = True
|
||||||
if user.premium_until and user.premium_until > datetime.now():
|
if user.premium_until and user.premium_until > datetime.now():
|
||||||
user.premium_until = user.premium_until + timedelta(days=30)
|
user.premium_until = user.premium_until + timedelta(days=30)
|
||||||
else:
|
else:
|
||||||
user.premium_until = datetime.now() + timedelta(days=30)
|
user.premium_until = datetime.now() + timedelta(days=30)
|
||||||
self.session.commit()
|
await self.session.commit()
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error activating premium: {e}")
|
print(f"Error activating premium: {e}")
|
||||||
self.session.rollback()
|
await self.session.rollback()
|
||||||
return False
|
return False
|
||||||
|
|||||||
@ -1,15 +1,19 @@
|
|||||||
from sqlalchemy import create_engine
|
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession
|
||||||
from sqlalchemy.orm import sessionmaker
|
|
||||||
from tg_bot.config.settings import settings
|
from tg_bot.config.settings import settings
|
||||||
|
|
||||||
engine = create_engine(
|
database_url = settings.DATABASE_URL
|
||||||
settings.DATABASE_URL,
|
if database_url.startswith("sqlite:///"):
|
||||||
|
database_url = database_url.replace("sqlite:///", "sqlite+aiosqlite:///")
|
||||||
|
|
||||||
|
engine = create_async_engine(
|
||||||
|
database_url,
|
||||||
echo=settings.DEBUG
|
echo=settings.DEBUG
|
||||||
)
|
)
|
||||||
|
|
||||||
SessionLocal = sessionmaker(bind=engine)
|
AsyncSessionLocal = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
|
||||||
|
|
||||||
def create_tables():
|
async def create_tables():
|
||||||
from .models import Base
|
from .models import Base
|
||||||
Base.metadata.create_all(bind=engine)
|
async with engine.begin() as conn:
|
||||||
|
await conn.run_sync(Base.metadata.create_all)
|
||||||
print(f"Таблицы созданы: {settings.DATABASE_URL}")
|
print(f"Таблицы созданы: {settings.DATABASE_URL}")
|
||||||
@ -32,6 +32,7 @@ async def create_bot() -> tuple[Bot, Dispatcher]:
|
|||||||
|
|
||||||
|
|
||||||
async def start_bot():
|
async def start_bot():
|
||||||
|
bot = None
|
||||||
try:
|
try:
|
||||||
bot, dp = await create_bot()
|
bot, dp = await create_bot()
|
||||||
|
|
||||||
@ -54,4 +55,5 @@ async def start_bot():
|
|||||||
logger.error(f"Ошибка запуска: {e}")
|
logger.error(f"Ошибка запуска: {e}")
|
||||||
raise
|
raise
|
||||||
finally:
|
finally:
|
||||||
await bot.session.close()
|
if bot:
|
||||||
|
await bot.session.close()
|
||||||
@ -4,8 +4,10 @@ from aiogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton
|
|||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from tg_bot.config.settings import settings
|
from tg_bot.config.settings import settings
|
||||||
from tg_bot.payment.yookassa.client import yookassa_client
|
from tg_bot.payment.yookassa.client import yookassa_client
|
||||||
from tg_bot.infrastructure.database.database import SessionLocal
|
from tg_bot.infrastructure.database.database import AsyncSessionLocal
|
||||||
from tg_bot.infrastructure.database.models import PaymentModel, UserModel
|
from tg_bot.infrastructure.database.models import PaymentModel
|
||||||
|
from tg_bot.domain.services.user_service import UserService
|
||||||
|
from sqlalchemy import select
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
@ -17,24 +19,23 @@ async def cmd_buy(message: Message):
|
|||||||
user_id = message.from_user.id
|
user_id = message.from_user.id
|
||||||
username = message.from_user.username or f"user_{user_id}"
|
username = message.from_user.username or f"user_{user_id}"
|
||||||
|
|
||||||
session = SessionLocal()
|
async with AsyncSessionLocal() as session:
|
||||||
try:
|
try:
|
||||||
user = session.query(UserModel).filter_by(
|
user_service = UserService(session)
|
||||||
telegram_id=str(user_id)
|
user = await user_service.get_user_by_telegram_id(user_id)
|
||||||
).first()
|
|
||||||
|
|
||||||
if user and user.is_premium and user.premium_until and user.premium_until > datetime.now():
|
if user and user.is_premium and user.premium_until and user.premium_until > datetime.now():
|
||||||
days_left = (user.premium_until - datetime.now()).days
|
days_left = (user.premium_until - datetime.now()).days
|
||||||
await message.answer(
|
await message.answer(
|
||||||
f"<b>У вас уже есть активная подписка!</b>\n\n"
|
f"<b>У вас уже есть активная подписка!</b>\n\n"
|
||||||
f"• Статус: Premium активен\n"
|
f"• Статус: Premium активен\n"
|
||||||
f"• Действует до: {user.premium_until.strftime('%d.%m.%Y')}\n"
|
f"• Действует до: {user.premium_until.strftime('%d.%m.%Y')}\n"
|
||||||
f"• Осталось дней: {days_left}\n\n"
|
f"• Осталось дней: {days_left}\n\n"
|
||||||
f"Новая подписка будет добавлена к текущей.",
|
f"Новая подписка будет добавлена к текущей.",
|
||||||
parse_mode="HTML"
|
parse_mode="HTML"
|
||||||
)
|
)
|
||||||
finally:
|
except Exception:
|
||||||
session.close()
|
pass
|
||||||
|
|
||||||
await message.answer(
|
await message.answer(
|
||||||
"*Создаю ссылку для оплаты...*\n\n"
|
"*Создаю ссылку для оплаты...*\n\n"
|
||||||
@ -49,25 +50,23 @@ async def cmd_buy(message: Message):
|
|||||||
user_id=user_id
|
user_id=user_id
|
||||||
)
|
)
|
||||||
|
|
||||||
session = SessionLocal()
|
async with AsyncSessionLocal() as session:
|
||||||
try:
|
try:
|
||||||
payment = PaymentModel(
|
payment = PaymentModel(
|
||||||
payment_id=str(uuid.uuid4()),
|
payment_id=str(uuid.uuid4()),
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
amount=str(settings.PAYMENT_AMOUNT),
|
amount=str(settings.PAYMENT_AMOUNT),
|
||||||
currency="RUB",
|
currency="RUB",
|
||||||
status="pending",
|
status="pending",
|
||||||
yookassa_payment_id=payment_data["id"],
|
yookassa_payment_id=payment_data["id"],
|
||||||
description="Оплата подписки VibeLawyerBot"
|
description="Оплата подписки VibeLawyerBot"
|
||||||
)
|
)
|
||||||
session.add(payment)
|
session.add(payment)
|
||||||
session.commit()
|
await session.commit()
|
||||||
print(f"Платёж сохранён в БД: {payment.payment_id}")
|
print(f"Платёж сохранён в БД: {payment.payment_id}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Ошибка сохранения платежа в БД: {e}")
|
print(f"Ошибка сохранения платежа в БД: {e}")
|
||||||
session.rollback()
|
await session.rollback()
|
||||||
finally:
|
|
||||||
session.close()
|
|
||||||
|
|
||||||
keyboard = InlineKeyboardMarkup(
|
keyboard = InlineKeyboardMarkup(
|
||||||
inline_keyboard=[
|
inline_keyboard=[
|
||||||
@ -140,49 +139,42 @@ async def check_payment_status(callback_query: types.CallbackQuery):
|
|||||||
payment = YooPayment.find_one(yookassa_id)
|
payment = YooPayment.find_one(yookassa_id)
|
||||||
|
|
||||||
if payment.status == "succeeded":
|
if payment.status == "succeeded":
|
||||||
session = SessionLocal()
|
async with AsyncSessionLocal() as session:
|
||||||
try:
|
try:
|
||||||
db_payment = session.query(PaymentModel).filter_by(
|
result = await session.execute(
|
||||||
yookassa_payment_id=yookassa_id
|
select(PaymentModel).filter_by(yookassa_payment_id=yookassa_id)
|
||||||
).first()
|
|
||||||
|
|
||||||
if db_payment:
|
|
||||||
db_payment.status = "succeeded"
|
|
||||||
user = session.query(UserModel).filter_by(
|
|
||||||
telegram_id=str(user_id)
|
|
||||||
).first()
|
|
||||||
|
|
||||||
if user:
|
|
||||||
user.is_premium = True
|
|
||||||
if user.premium_until and user.premium_until > datetime.now():
|
|
||||||
user.premium_until = user.premium_until + timedelta(days=30)
|
|
||||||
else:
|
|
||||||
user.premium_until = datetime.now() + timedelta(days=30)
|
|
||||||
|
|
||||||
session.commit()
|
|
||||||
user = session.query(UserModel).filter_by(
|
|
||||||
telegram_id=str(user_id)
|
|
||||||
).first()
|
|
||||||
|
|
||||||
await callback_query.message.answer(
|
|
||||||
"<b>Оплата подтверждена!</b>\n\n"
|
|
||||||
f"Ваш premium-доступ активирован до: "
|
|
||||||
f"<b>{user.premium_until.strftime('%d.%m.%Y')}</b>\n\n"
|
|
||||||
"Теперь вы можете:\n"
|
|
||||||
"• Задавать неограниченное количество вопросов\n"
|
|
||||||
"• Получать приоритетные ответы\n"
|
|
||||||
"• Использовать все функции бота\n\n"
|
|
||||||
"<i>Спасибо за покупку!</i>",
|
|
||||||
parse_mode="HTML"
|
|
||||||
)
|
)
|
||||||
else:
|
db_payment = result.scalar_one_or_none()
|
||||||
await callback_query.message.answer(
|
|
||||||
"<b>Платёж найден в ЮKассе, но не в нашей БД</b>\n\n"
|
if db_payment:
|
||||||
"Пожалуйста, обратитесь к администратору.",
|
db_payment.status = "succeeded"
|
||||||
parse_mode="HTML"
|
user_service = UserService(session)
|
||||||
)
|
success = await user_service.activate_premium(user_id)
|
||||||
finally:
|
if success:
|
||||||
session.close()
|
user = await user_service.get_user_by_telegram_id(user_id)
|
||||||
|
await session.commit()
|
||||||
|
if not user:
|
||||||
|
user = await user_service.get_user_by_telegram_id(user_id)
|
||||||
|
|
||||||
|
await callback_query.message.answer(
|
||||||
|
"<b>Оплата подтверждена!</b>\n\n"
|
||||||
|
f"Ваш premium-доступ активирован до: "
|
||||||
|
f"<b>{user.premium_until.strftime('%d.%m.%Y')}</b>\n\n"
|
||||||
|
"Теперь вы можете:\n"
|
||||||
|
"• Задавать неограниченное количество вопросов\n"
|
||||||
|
"• Получать приоритетные ответы\n"
|
||||||
|
"• Использовать все функции бота\n\n"
|
||||||
|
"<i>Спасибо за покупку!</i>",
|
||||||
|
parse_mode="HTML"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await callback_query.message.answer(
|
||||||
|
"<b>Платёж найден в ЮKассе, но не в нашей БД</b>\n\n"
|
||||||
|
"Пожалуйста, обратитесь к администратору.",
|
||||||
|
parse_mode="HTML"
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Ошибка обработки платежа: {e}")
|
||||||
|
|
||||||
elif payment.status == "pending":
|
elif payment.status == "pending":
|
||||||
await callback_query.message.answer(
|
await callback_query.message.answer(
|
||||||
@ -212,45 +204,44 @@ async def check_payment_status(callback_query: types.CallbackQuery):
|
|||||||
parse_mode="HTML"
|
parse_mode="HTML"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.message(Command("mypayments"))
|
@router.message(Command("mypayments"))
|
||||||
async def cmd_my_payments(message: Message):
|
async def cmd_my_payments(message: Message):
|
||||||
user_id = message.from_user.id
|
user_id = message.from_user.id
|
||||||
|
|
||||||
session = SessionLocal()
|
async with AsyncSessionLocal() as session:
|
||||||
try:
|
try:
|
||||||
payments = session.query(PaymentModel).filter_by(
|
result = await session.execute(
|
||||||
user_id=user_id
|
select(PaymentModel).filter_by(user_id=user_id).order_by(PaymentModel.created_at.desc()).limit(10)
|
||||||
).order_by(PaymentModel.created_at.desc()).limit(10).all()
|
)
|
||||||
|
payments = result.scalars().all()
|
||||||
|
|
||||||
|
if not payments:
|
||||||
|
await message.answer(
|
||||||
|
"<b>У вас пока нет платежей</b>\n\n"
|
||||||
|
"Используйте команду /buy чтобы оформить подписку.",
|
||||||
|
parse_mode="HTML"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
response = ["<b>Ваши последние платежи:</b>\n"]
|
||||||
|
|
||||||
|
for i, payment in enumerate(payments, 1):
|
||||||
|
status_text = "Успешно" if payment.status == "succeeded" else "Ожидание" if payment.status == "pending" else "Ошибка"
|
||||||
|
response.append(
|
||||||
|
f"\n<b>{i}. {payment.amount} руб. ({status_text})</b>\n"
|
||||||
|
f"Статус: {payment.status}\n"
|
||||||
|
f"Дата: {payment.created_at.strftime('%d.%m.%Y %H:%M')}\n"
|
||||||
|
f"ID: <code>{payment.payment_id[:8]}...</code>"
|
||||||
|
)
|
||||||
|
|
||||||
|
response.append("\n\n<i>Полный доступ открывается после успешной оплаты</i>")
|
||||||
|
|
||||||
if not payments:
|
|
||||||
await message.answer(
|
await message.answer(
|
||||||
"<b>У вас пока нет платежей</b>\n\n"
|
"\n".join(response),
|
||||||
"Используйте команду /buy чтобы оформить подписку.",
|
|
||||||
parse_mode="HTML"
|
parse_mode="HTML"
|
||||||
)
|
)
|
||||||
return
|
except Exception as e:
|
||||||
|
print(f"Ошибка получения платежей: {e}")
|
||||||
response = ["<b>Ваши последние платежи:</b>\n"]
|
|
||||||
|
|
||||||
for i, payment in enumerate(payments, 1):
|
|
||||||
status_text = "Успешно" if payment.status == "succeeded" else "Ожидание" if payment.status == "pending" else "Ошибка"
|
|
||||||
response.append(
|
|
||||||
f"\n<b>{i}. {payment.amount} руб. ({status_text})</b>\n"
|
|
||||||
f"Статус: {payment.status}\n"
|
|
||||||
f"Дата: {payment.created_at.strftime('%d.%m.%Y %H:%M')}\n"
|
|
||||||
f"ID: <code>{payment.payment_id[:8]}...</code>"
|
|
||||||
)
|
|
||||||
|
|
||||||
response.append("\n\n<i>Полный доступ открывается после успешной оплаты</i>")
|
|
||||||
|
|
||||||
await message.answer(
|
|
||||||
"\n".join(response),
|
|
||||||
parse_mode="HTML"
|
|
||||||
)
|
|
||||||
|
|
||||||
finally:
|
|
||||||
session.close()
|
|
||||||
|
|
||||||
|
|
||||||
@router.message(Command("testcards"))
|
@router.message(Command("testcards"))
|
||||||
|
|||||||
@ -3,8 +3,9 @@ from aiogram.types import Message
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import aiohttp
|
import aiohttp
|
||||||
from tg_bot.config.settings import settings
|
from tg_bot.config.settings import settings
|
||||||
from tg_bot.infrastructure.database.database import SessionLocal
|
from tg_bot.infrastructure.database.database import AsyncSessionLocal
|
||||||
from tg_bot.infrastructure.database.models import UserModel
|
from tg_bot.infrastructure.database.models import UserModel
|
||||||
|
from tg_bot.domain.services.user_service import UserService
|
||||||
from tg_bot.application.services.rag_service import RAGService
|
from tg_bot.application.services.rag_service import RAGService
|
||||||
|
|
||||||
router = Router()
|
router = Router()
|
||||||
@ -18,41 +19,35 @@ async def handle_question(message: Message):
|
|||||||
if question_text.startswith('/'):
|
if question_text.startswith('/'):
|
||||||
return
|
return
|
||||||
|
|
||||||
session = SessionLocal()
|
async with AsyncSessionLocal() as session:
|
||||||
try:
|
try:
|
||||||
user = session.query(UserModel).filter_by(
|
user_service = UserService(session)
|
||||||
telegram_id=str(user_id)
|
user = await user_service.get_user_by_telegram_id(user_id)
|
||||||
).first()
|
|
||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
user = UserModel(
|
user = await user_service.get_or_create_user(
|
||||||
telegram_id=str(user_id),
|
user_id,
|
||||||
username=message.from_user.username or "",
|
message.from_user.username or "",
|
||||||
first_name=message.from_user.first_name or "",
|
message.from_user.first_name or "",
|
||||||
last_name=message.from_user.last_name or ""
|
message.from_user.last_name or ""
|
||||||
|
)
|
||||||
|
await ensure_user_in_backend(str(user_id), message.from_user)
|
||||||
|
|
||||||
|
if user.is_premium:
|
||||||
|
await process_premium_question(message, user, question_text, user_service)
|
||||||
|
|
||||||
|
elif user.questions_used < settings.FREE_QUESTIONS_LIMIT:
|
||||||
|
await process_free_question(message, user, question_text, user_service)
|
||||||
|
|
||||||
|
else:
|
||||||
|
await handle_limit_exceeded(message, user)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error processing question: {e}")
|
||||||
|
await message.answer(
|
||||||
|
"Произошла ошибка. Попробуйте позже.",
|
||||||
|
parse_mode="HTML"
|
||||||
)
|
)
|
||||||
session.add(user)
|
|
||||||
session.commit()
|
|
||||||
|
|
||||||
await ensure_user_in_backend(str(user_id), message.from_user)
|
|
||||||
|
|
||||||
if user.is_premium:
|
|
||||||
await process_premium_question(message, user, question_text, session)
|
|
||||||
|
|
||||||
elif user.questions_used < settings.FREE_QUESTIONS_LIMIT:
|
|
||||||
await process_free_question(message, user, question_text, session)
|
|
||||||
|
|
||||||
else:
|
|
||||||
await handle_limit_exceeded(message, user)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error processing question: {e}")
|
|
||||||
await message.answer(
|
|
||||||
"Произошла ошибка. Попробуйте позже.",
|
|
||||||
parse_mode="HTML"
|
|
||||||
)
|
|
||||||
finally:
|
|
||||||
session.close()
|
|
||||||
|
|
||||||
|
|
||||||
async def ensure_user_in_backend(telegram_id: str, telegram_user):
|
async def ensure_user_in_backend(telegram_id: str, telegram_user):
|
||||||
@ -74,9 +69,8 @@ async def ensure_user_in_backend(telegram_id: str, telegram_user):
|
|||||||
print(f"Error creating user in backend: {e}")
|
print(f"Error creating user in backend: {e}")
|
||||||
|
|
||||||
|
|
||||||
async def process_premium_question(message: Message, user: UserModel, question_text: str, session):
|
async def process_premium_question(message: Message, user: UserModel, question_text: str, user_service: UserService):
|
||||||
user.questions_used += 1
|
await user_service.update_user_questions(user.telegram_id)
|
||||||
session.commit()
|
|
||||||
|
|
||||||
await message.bot.send_chat_action(message.chat.id, "typing")
|
await message.bot.send_chat_action(message.chat.id, "typing")
|
||||||
|
|
||||||
@ -135,10 +129,10 @@ async def process_premium_question(message: Message, user: UserModel, question_t
|
|||||||
await message.answer(response, parse_mode="HTML")
|
await message.answer(response, parse_mode="HTML")
|
||||||
|
|
||||||
|
|
||||||
async def process_free_question(message: Message, user: UserModel, question_text: str, session):
|
async def process_free_question(message: Message, user: UserModel, question_text: str, user_service: UserService):
|
||||||
user.questions_used += 1
|
await user_service.update_user_questions(user.telegram_id)
|
||||||
|
user = await user_service.get_user_by_telegram_id(user.telegram_id)
|
||||||
remaining = settings.FREE_QUESTIONS_LIMIT - user.questions_used
|
remaining = settings.FREE_QUESTIONS_LIMIT - user.questions_used
|
||||||
session.commit()
|
|
||||||
|
|
||||||
await message.bot.send_chat_action(message.chat.id, "typing")
|
await message.bot.send_chat_action(message.chat.id, "typing")
|
||||||
|
|
||||||
|
|||||||
@ -4,8 +4,8 @@ from aiogram.types import Message
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from tg_bot.config.settings import settings
|
from tg_bot.config.settings import settings
|
||||||
from tg_bot.infrastructure.database.database import SessionLocal
|
from tg_bot.infrastructure.database.database import AsyncSessionLocal
|
||||||
from tg_bot.infrastructure.database.models import UserModel
|
from tg_bot.domain.services.user_service import UserService
|
||||||
|
|
||||||
router = Router()
|
router = Router()
|
||||||
|
|
||||||
@ -16,33 +16,22 @@ async def cmd_start(message: Message):
|
|||||||
username = message.from_user.username or ""
|
username = message.from_user.username or ""
|
||||||
first_name = message.from_user.first_name or ""
|
first_name = message.from_user.first_name or ""
|
||||||
last_name = message.from_user.last_name or ""
|
last_name = message.from_user.last_name or ""
|
||||||
session = SessionLocal()
|
async with AsyncSessionLocal() as session:
|
||||||
try:
|
try:
|
||||||
user = session.query(UserModel).filter_by(
|
user_service = UserService(session)
|
||||||
telegram_id=str(user_id)
|
existing_user = await user_service.get_user_by_telegram_id(user_id)
|
||||||
).first()
|
user = await user_service.get_or_create_user(
|
||||||
|
user_id,
|
||||||
if not user:
|
username,
|
||||||
user = UserModel(
|
first_name,
|
||||||
telegram_id=str(user_id),
|
last_name
|
||||||
username=username,
|
|
||||||
first_name=first_name,
|
|
||||||
last_name=last_name
|
|
||||||
)
|
)
|
||||||
session.add(user)
|
if not existing_user:
|
||||||
session.commit()
|
print(f"Новый пользователь: {user_id}")
|
||||||
print(f"Новый пользователь: {user_id}")
|
|
||||||
else:
|
|
||||||
user.username = username
|
|
||||||
user.first_name = first_name
|
|
||||||
user.last_name = last_name
|
|
||||||
session.commit()
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Ошибка сохранения пользователя: {e}")
|
print(f"Ошибка сохранения пользователя: {e}")
|
||||||
session.rollback()
|
await session.rollback()
|
||||||
finally:
|
|
||||||
session.close()
|
|
||||||
welcome_text = (
|
welcome_text = (
|
||||||
f"<b>Привет, {first_name}!</b>\n\n"
|
f"<b>Привет, {first_name}!</b>\n\n"
|
||||||
f"Я <b>VibeLawyerBot</b> - ваш помощник в юридических вопросах.\n\n"
|
f"Я <b>VibeLawyerBot</b> - ваш помощник в юридических вопросах.\n\n"
|
||||||
|
|||||||
@ -4,8 +4,8 @@ from aiogram.filters import Command
|
|||||||
from aiogram.types import Message
|
from aiogram.types import Message
|
||||||
|
|
||||||
from tg_bot.config.settings import settings
|
from tg_bot.config.settings import settings
|
||||||
from tg_bot.infrastructure.database.database import SessionLocal
|
from tg_bot.infrastructure.database.database import AsyncSessionLocal
|
||||||
from tg_bot.infrastructure.database.models import UserModel
|
from tg_bot.domain.services.user_service import UserService
|
||||||
|
|
||||||
router = Router()
|
router = Router()
|
||||||
|
|
||||||
@ -14,52 +14,48 @@ router = Router()
|
|||||||
async def cmd_stats(message: Message):
|
async def cmd_stats(message: Message):
|
||||||
user_id = message.from_user.id
|
user_id = message.from_user.id
|
||||||
|
|
||||||
session = SessionLocal()
|
async with AsyncSessionLocal() as session:
|
||||||
try:
|
try:
|
||||||
user = session.query(UserModel).filter_by(
|
user_service = UserService(session)
|
||||||
telegram_id=str(user_id)
|
user = await user_service.get_user_by_telegram_id(user_id)
|
||||||
).first()
|
|
||||||
|
|
||||||
if user:
|
if user:
|
||||||
stats_text = (
|
stats_text = (
|
||||||
f"<b>Ваша статистика</b>\n\n"
|
f"<b>Ваша статистика</b>\n\n"
|
||||||
f"<b>Основное:</b>\n"
|
f"<b>Основное:</b>\n"
|
||||||
f"• ID: <code>{user_id}</code>\n"
|
f"• ID: <code>{user_id}</code>\n"
|
||||||
f"• Premium: {'Да' if user.is_premium else 'Нет'}\n"
|
f"• Premium: {'Да' if user.is_premium else 'Нет'}\n"
|
||||||
f"• Вопросов использовано: {user.questions_used}/{settings.FREE_QUESTIONS_LIMIT}\n\n"
|
f"• Вопросов использовано: {user.questions_used}/{settings.FREE_QUESTIONS_LIMIT}\n\n"
|
||||||
)
|
|
||||||
|
|
||||||
if user.is_premium:
|
|
||||||
stats_text += (
|
|
||||||
f"<b>Premium статус:</b>\n"
|
|
||||||
f"• Активен до: {user.premium_until.strftime('%d.%m.%Y') if user.premium_until else 'Не указано'}\n"
|
|
||||||
f"• Лимит вопросов: безлимитно\n\n"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if user.is_premium:
|
||||||
|
stats_text += (
|
||||||
|
f"<b>Premium статус:</b>\n"
|
||||||
|
f"• Активен до: {user.premium_until.strftime('%d.%m.%Y') if user.premium_until else 'Не указано'}\n"
|
||||||
|
f"• Лимит вопросов: безлимитно\n\n"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
remaining = max(0, settings.FREE_QUESTIONS_LIMIT - user.questions_used)
|
||||||
|
stats_text += (
|
||||||
|
f"<b>Бесплатный доступ:</b>\n"
|
||||||
|
f"• Осталось вопросов: {remaining}\n"
|
||||||
|
f"• Для безлимита: /buy\n\n"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
remaining = max(0, settings.FREE_QUESTIONS_LIMIT - user.questions_used)
|
stats_text = (
|
||||||
stats_text += (
|
f"<b>Добро пожаловать!</b>\n\n"
|
||||||
f"<b>Бесплатный доступ:</b>\n"
|
f"Вы новый пользователь.\n"
|
||||||
f"• Осталось вопросов: {remaining}\n"
|
f"• Ваш ID: <code>{user_id}</code>\n"
|
||||||
f"• Для безлимита: /buy\n\n"
|
f"• Бесплатных вопросов: {settings.FREE_QUESTIONS_LIMIT}\n"
|
||||||
|
f"• Для начала работы просто задайте вопрос!\n\n"
|
||||||
|
f"<i>Используйте /buy для получения полного доступа</i>"
|
||||||
)
|
)
|
||||||
|
|
||||||
else:
|
await message.answer(stats_text, parse_mode="HTML")
|
||||||
stats_text = (
|
|
||||||
f"<b>Добро пожаловать!</b>\n\n"
|
except Exception as e:
|
||||||
f"Вы новый пользователь.\n"
|
await message.answer(
|
||||||
f"• Ваш ID: <code>{user_id}</code>\n"
|
f"<b>Ошибка получения статистики</b>\n\n"
|
||||||
f"• Бесплатных вопросов: {settings.FREE_QUESTIONS_LIMIT}\n"
|
f"Попробуйте позже.",
|
||||||
f"• Для начала работы просто задайте вопрос!\n\n"
|
parse_mode="HTML"
|
||||||
f"<i>Используйте /buy для получения полного доступа</i>"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
await message.answer(stats_text, parse_mode="HTML")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
await message.answer(
|
|
||||||
f"<b>Ошибка получения статистики</b>\n\n"
|
|
||||||
f"Попробуйте позже.",
|
|
||||||
parse_mode="HTML"
|
|
||||||
)
|
|
||||||
finally:
|
|
||||||
session.close()
|
|
||||||
|
|||||||
@ -19,47 +19,48 @@ async def handle_yookassa_webhook(request: Request):
|
|||||||
try:
|
try:
|
||||||
from tg_bot.config.settings import settings
|
from tg_bot.config.settings import settings
|
||||||
from tg_bot.domain.services.user_service import UserService
|
from tg_bot.domain.services.user_service import UserService
|
||||||
from tg_bot.infrastructure.database.database import SessionLocal
|
from tg_bot.infrastructure.database.database import AsyncSessionLocal
|
||||||
from tg_bot.infrastructure.database.models import UserModel
|
from tg_bot.infrastructure.database.models import UserModel
|
||||||
|
from sqlalchemy import select
|
||||||
from aiogram import Bot
|
from aiogram import Bot
|
||||||
|
|
||||||
session = SessionLocal()
|
|
||||||
if event_type == "payment.succeeded":
|
if event_type == "payment.succeeded":
|
||||||
payment = data.get("object", {})
|
payment = data.get("object", {})
|
||||||
user_id = payment.get("metadata", {}).get("user_id")
|
user_id = payment.get("metadata", {}).get("user_id")
|
||||||
|
|
||||||
if user_id:
|
if user_id:
|
||||||
user_service = UserService(session)
|
async with AsyncSessionLocal() as session:
|
||||||
success = await user_service.activate_premium(int(user_id))
|
user_service = UserService(session)
|
||||||
if success:
|
success = await user_service.activate_premium(int(user_id))
|
||||||
print(f"Premium activated for user {user_id}")
|
if success:
|
||||||
|
print(f"Premium activated for user {user_id}")
|
||||||
|
|
||||||
user = session.query(UserModel).filter_by(
|
result = await session.execute(
|
||||||
telegram_id=str(user_id)
|
select(UserModel).filter_by(telegram_id=str(user_id))
|
||||||
).first()
|
)
|
||||||
|
user = result.scalar_one_or_none()
|
||||||
|
|
||||||
if user and settings.TELEGRAM_BOT_TOKEN:
|
if user and settings.TELEGRAM_BOT_TOKEN:
|
||||||
try:
|
try:
|
||||||
bot = Bot(token=settings.TELEGRAM_BOT_TOKEN)
|
bot = Bot(token=settings.TELEGRAM_BOT_TOKEN)
|
||||||
premium_until = user.premium_until or datetime.now() + timedelta(days=30)
|
premium_until = user.premium_until or datetime.now() + timedelta(days=30)
|
||||||
|
|
||||||
notification = (
|
notification = (
|
||||||
f"<b>Оплата подтверждена!</b>\n\n"
|
f"<b>Оплата подтверждена!</b>\n\n"
|
||||||
f"Premium активирован до {premium_until.strftime('%d.%m.%Y')}"
|
f"Premium активирован до {premium_until.strftime('%d.%m.%Y')}"
|
||||||
)
|
)
|
||||||
|
|
||||||
await bot.send_message(
|
await bot.send_message(
|
||||||
chat_id=int(user_id),
|
chat_id=int(user_id),
|
||||||
text=notification,
|
text=notification,
|
||||||
parse_mode="HTML"
|
parse_mode="HTML"
|
||||||
)
|
)
|
||||||
print(f"Notification sent to user {user_id}")
|
print(f"Notification sent to user {user_id}")
|
||||||
await bot.session.close()
|
await bot.session.close()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error sending notification: {e}")
|
print(f"Error sending notification: {e}")
|
||||||
else:
|
else:
|
||||||
print(f"User {user_id} not found")
|
print(f"User {user_id} not found")
|
||||||
session.close()
|
|
||||||
|
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
print(f"Import error: {e}")
|
print(f"Import error: {e}")
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user