From 4dfa80ffae15a20933a30edd0e25d7f67d74da41 Mon Sep 17 00:00:00 2001 From: Disledg Date: Mon, 7 Oct 2024 20:38:44 +0300 Subject: [PATCH] =?UTF-8?q?-=20=D0=9D=D0=B5=D0=B1=D0=BE=D0=BB=D1=8C=D1=88?= =?UTF-8?q?=D0=B0=D1=8F=20=D1=80=D0=B5=D0=BE=D1=80=D0=B3=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D0=BA=D0=BE=D0=B4=D0=B0=20?= =?UTF-8?q?=D0=B2=20bd=20-=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=8B=20?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D1=8E=20~=20=D0=B2=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D1=86=D0=B5=D1=81=D1=81=D0=B5=20-=20=D0=9F=D0=B5=D1=80=D0=B5?= =?UTF-8?q?=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D1=83=20tarif=5Fsetting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bot.py | 109 ++++++++++++++++++++++++++++++++++++----------- db.py | 37 ---------------- db_operations.py | 74 ++++++++++++++++++++++++++++++++ service.py | 27 +++++++----- 4 files changed, 173 insertions(+), 74 deletions(-) create mode 100644 db_operations.py diff --git a/bot.py b/bot.py index 6ba257b..d9b1fdd 100644 --- a/bot.py +++ b/bot.py @@ -2,14 +2,15 @@ from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update from telegram.ext import Application, CallbackQueryHandler, CommandHandler, ContextTypes from db import User, VPNServer, Transaction, Subscription -from db import last_subscription, create_user , get_sub_list -import db -from sqlalchemy import desc -import json -import string -from datetime import datetime from db import get_db_session from db import init_db, SessionLocal +from db_operations import last_subscription, create_user , get_sub_list,buy_sub +from sqlalchemy import desc + +import json + +from datetime import datetime + from logger_config import setup_logger with open('config.json', 'r') as file: config = json.load(file) @@ -42,19 +43,29 @@ async def personal_account(update: Update, context: ContextTypes.DEFAULT_TYPE) - session = next(get_db_session()) - if session.query(User).filter(User.telegram_id == str(update.effective_user.id)).first() == None: - create_user(str(update.effective_user.id),update.effective_user.username) - user = session.query(User).filter(User.telegram_id == str(update.effective_user.id)).first() + if session.query(User).filter(User.telegram_id == str(update.callback_query.from_user.id)).first() == None: + create_user(str(update.callback_query.from_user.id),update.effective_user.username) + user = session.query(User).filter(User.telegram_id == str(update.callback_query.from_user.id)).first() subscription = last_subscription(session=session,user=user) + loading_message = await context.bot.send_message(chat_id=update.callback_query.message.chat.id, text="Загрузка...") + loading_message_id = loading_message.message_id # Сохраняем ID сообщения + if not subscription: - await update.message.reply_text(f'Профиль {user.username}\nВы не приобретали ещё у нас подписку, но это явно стоит сделать:)',reply_markup=reply_markup) - # проверяем, истекла ли подписка + await loading_message_id.edit_text( + f'Профиль {user.username}, {user.telegram_id}\nВы не приобретали ещё у нас подписку, но это явно стоит сделать:)\nВаш счёт составляет: {user.balance}' + ) + # Проверяем, истекла ли подписка elif subscription.expiry_date < datetime.now(): - await update.message.reply_text(f'Ваш профиль {user.username},Ваша подписка действует до - {subscription.expiry_date}',reply_markup=reply_markup) + await loading_message_id.edit_text( + f'Ваш профиль {user.username}, {user.telegram_id}, Ваша подписка действует до - {subscription.expiry_date}' + ) else: - await update.message.reply_text(f'Ваш профиль {user.username},\nВаша подписка истекла - {subscription.expiry_date}',reply_markup=reply_markup) + await loading_message_id.edit_text( + f'Ваш профиль {user.username}, {user.telegram_id},\nВаша подписка истекла - {subscription.expiry_date}' + ) + async def about(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: keyboard = [ @@ -62,7 +73,7 @@ async def about(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: InlineKeyboardButton("Главное меню", callback_data="account") ]] reply_markup = InlineKeyboardMarkup(keyboard) - await update.message.reply_text(f'Игорь чё нить напишет, я продублирую',reply_markup=reply_markup) + await update.callback_query.message.reply_text(f'Игорь чё нить напишет, я продублирую',reply_markup=reply_markup) async def support(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: keyboard = [ @@ -71,7 +82,7 @@ async def support(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: InlineKeyboardButton("Написать", callback_data="sup") # Нужно через каллбек доделать ]] reply_markup = InlineKeyboardMarkup(keyboard) - await update.message.reply_text(f'Что бы отправить сообщение поддержке выберите в меню кнопку "Написать", а далее изложите в одном сообщении свою ошибку.',reply_markup=reply_markup) + await update.callback_query.message.reply_text(f'Что бы отправить сообщение поддержке выберите в меню кнопку "Написать", а далее изложите в одном сообщении свою ошибку.',reply_markup=reply_markup) async def pop_up(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: keyboard = [ @@ -79,7 +90,7 @@ async def pop_up(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: InlineKeyboardButton("Главное меню", callback_data="account"), ]] reply_markup = InlineKeyboardMarkup(keyboard) - await update.message.reply_text(f'Когда нибудь эта штука заработает',reply_markup=reply_markup) + await update.callback_query.message.reply_text(f'Когда нибудь эта штука заработает',reply_markup=reply_markup) async def buy_subscription(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: keyboard = [ @@ -88,22 +99,25 @@ async def buy_subscription(update: Update, context: ContextTypes.DEFAULT_TYPE) - ]] reply_markup = InlineKeyboardMarkup(keyboard) session = next(get_db_session()) - user = session.query(User).filter(User.telegram_id == str(update.effective_user.id)).first() + user = session.query(User).filter(User.telegram_id == str(update.callback_query.from_user.id)).first() check = last_subscription(session=session,user=user) if not check: keyboard = [ [ - InlineKeyboardButton("Тариф 1 \"Бимжик\"", callback_data="bimzhik"), + InlineKeyboardButton("Тариф 1 \"Бимжик\"", callback_data="Бимжик"), ], [ - InlineKeyboardButton("Тариф 2 \"Бизнес хомячёк\"", callback_data="homyachok"), + InlineKeyboardButton("Тариф 2 \"Бизнес хомячёк\"", callback_data="Бизнес_хомячёк"), ], [ - InlineKeyboardButton("Тариф 2 \"Продвинутый Акулёнок\"", callback_data="akulenok"), + InlineKeyboardButton("Тариф 3 \"Продвинутый Акулёнок\"", callback_data="Продвинутый_Акулёнок"), + ], + [ + InlineKeyboardButton("Главное меню", callback_data="account"), ]] reply_markup = InlineKeyboardMarkup(keyboard) - await update.message.reply_text(f'Какую подписку вы хотели бы приобрести\nТариф 1 "Бимжик" - 200 рубликов - 1 месяцок\nТариф 2 "Бизнес хомячёк" - 500 рубликов - 3 месяцка\nТариф 3 "Продвинутый Акулёнок" - 888 рубликов - 888 рубликов\n',reply_markup=reply_markup) + await update.callback_query.message.reply_text(f'Какую подписку вы хотели бы приобрести\nТариф 1 "Бимжик" - 200 рубликов - 1 месяцок\nТариф 2 "Бизнес хомячёк" - 500 рубликов - 3 месяцка\nТариф 3 "Продвинутый Акулёнок" - 888 рубликов - 6 месяцков\n',reply_markup=reply_markup) # проверяем, истекла ли подписка else: keyboard = [ @@ -111,7 +125,7 @@ async def buy_subscription(update: Update, context: ContextTypes.DEFAULT_TYPE) - InlineKeyboardButton("Главное меню", callback_data="account"), ]] reply_markup = InlineKeyboardMarkup(keyboard) - await update.message.reply_text(f'У вас уже приобретена подписка',reply_markup=reply_markup) + await update.callback_query.message.reply_text(f'У вас уже приобретена подписка',reply_markup=reply_markup) async def faq(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: @@ -120,7 +134,50 @@ async def faq(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: InlineKeyboardButton("Главное меню", callback_data="account"), ]] reply_markup = InlineKeyboardMarkup(keyboard) - await update.message.reply_text(f'Когда нибудь что нибудь здесь будет написано!!;)',reply_markup=reply_markup) + await update.callback_query.message.reply_text(f'Когда нибудь что нибудь здесь будет написано!!;)',reply_markup=reply_markup) + +async def button_handler(update: Update, context): + query = update.callback_query + + loading_message = await query.message.reply_text("Загрузка...") + + await query.answer() + + session = next(get_db_session()) + try: + if query.data == 'account': + await personal_account(update, context=context) + elif query.data == 'about': + await about(update, context) + elif query.data == 'support': + await support(update, context) + elif query.data == 'pop_up': + await pop_up(update, context) + elif query.data == 'buy_tarif': + await buy_subscription(update, context) + elif query.data == 'faq': + await faq(update, context) + elif query.data == 'payment_history': + await active_sub(update, context) + + if query.data in ['Бимжик', 'Бизнес_хомячёк', 'Продвинутый_Акулёнок']: + plan = query.data.replace('_', ' ') if '_' in query.data else query.data + check = buy_sub(session, query.from_user.id, plan, logger) + + + if check != "OK": + await loading_message.edit_text("Неизвестный тариф.") + else: + await loading_message.edit_text("Тариф успешно установлен!") + + except Exception as e: + logger.error(f"Ошибка при обработке запроса пользователя {query.from_user.id}: {e}") + await loading_message.edit_text("Произошла ошибка. Пожалуйста, попробуйте снова.") + finally: + session.close() + + + async def active_sub(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: keyboard = [ [ @@ -128,7 +185,7 @@ async def active_sub(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None ]] reply_markup = InlineKeyboardMarkup(keyboard) session = next(get_db_session()) - list_sub = get_sub_list(session, 10, update.effective_user.id) + list_sub = get_sub_list(session, 10, update.callback_query.from_user.id) if list_sub: message = "Ваши подписки:\n" @@ -139,10 +196,9 @@ async def active_sub(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None message += f" Устаревшая: {cur_sub.plan}, Дата покупки: {cur_sub.created_at}\n" else: message = "Ты пидор, не приобрел у нас подписку?!" - await update.message.reply_text(message,reply_markup=reply_markup) + await update.callback_query.message.reply_text(message,reply_markup=reply_markup) def main() -> None: - init_db() db = SessionLocal() application = Application.builder().token(config['token']).build() @@ -155,6 +211,7 @@ def main() -> None: application.add_handler(CommandHandler("buy_subscription", buy_subscription)) application.add_handler(CommandHandler("faq", faq)) application.add_handler(CommandHandler("active_sub", active_sub)) + application.add_handler(CallbackQueryHandler(button_handler)) application.run_polling(allowed_updates=Update.ALL_TYPES) diff --git a/db.py b/db.py index 7156134..495535a 100644 --- a/db.py +++ b/db.py @@ -13,43 +13,6 @@ def generate_uuid(): return str(uuid.uuid4()) -def last_subscription(session,user): - last_subscription = ( - session.query(Subscription) - .filter(Subscription.user_id == user.id) - .order_by(desc(Subscription.created_at)) - .first() - ) - return last_subscription -def get_sub_list(session,count,user_id): - subscriptions = ( - session.query(Subscription) - .filter(Subscription.user_id == str(user_id)) - .order_by(desc(Subscription.created_at)) - .limit(count) # Ограничиваем результат 10 записями - .all() # Получаем все записи - ) - return subscriptions - -def create_user(telegram_id: str, username: str = None, balance: float = 0.0): - db = next(get_db_session()) - try: - new_user = User( - telegram_id=telegram_id, - username=username, - balance=balance - ) - db.add(new_user) - db.commit() - db.refresh(new_user) - return new_user - except Exception as e: - db.rollback() - raise e - finally: - db.close() - - #Пользователи class User(Base): __tablename__ = 'users' diff --git a/db_operations.py b/db_operations.py new file mode 100644 index 0000000..be5d785 --- /dev/null +++ b/db_operations.py @@ -0,0 +1,74 @@ + +from service import UserService + +#DataBase +from sqlalchemy import desc +from db import get_db_session +from db import User +from db import Subscription +from db import Transaction +from db import VPNServer + +import json + +with open('config.json', 'r') as file: + config = json.load(file) + + +def last_subscription(session,user): + last_subscription = ( + session.query(Subscription) + .filter(Subscription.user_id == user.id) + .order_by(desc(Subscription.created_at)) + .first() + ) + return last_subscription +def get_sub_list(session,count,user_id): + subscriptions = ( + session.query(Subscription) + .filter(Subscription.user_id == str(user_id)) + .order_by(desc(Subscription.created_at)) + .limit(count) # Ограничиваем результат 10 записями + .all() # Получаем все записи + ) + return subscriptions + +def create_user(telegram_id: str, username: str = None, balance: float = 0.0): + db = next(get_db_session()) + try: + new_user = User( + telegram_id=telegram_id, + username=username, + balance=balance + ) + db.add(new_user) + db.commit() + db.refresh(new_user) + return new_user + except Exception as e: + db.rollback() + raise e + finally: + db.close() + +def buy_sub(session, telegram_id: str, plan: str, logger): + try: + user = session.query(User).filter(User.telegram_id == str(telegram_id)).first() + if user is None: + logger.error(f"Пользователь с Telegram ID {telegram_id} не найден.") + return "error" + + current_plan = config['subscription_templates'].get(plan) + if current_plan is None: + logger.error(f"Тариф {plan} не найден в шаблонах.") + return "error" + + if user.balance == current_plan['cost']: + service = UserService(logger) + service.tariff_setting(user, plan, current_plan['duration']) + return "OK" + else: + logger.error(f"Недостаточно средств на счету пользователя {telegram_id} для тарифа {plan}.") + return "error" + except Exception as e: + logger.error(f"Ошибка при покупке тарифа для пользователя {telegram_id}: {e}") diff --git a/service.py b/service.py index 6d1f010..502cf14 100644 --- a/service.py +++ b/service.py @@ -2,6 +2,7 @@ from db import User from db import Subscription from db import Transaction from db import VPNServer +from sqlalchemy import desc from datetime import datetime,timedelta from db import get_db_session import json @@ -62,27 +63,31 @@ class UserService: finally: session.close() - def tariff_setting(self,telegram_id: int,plan: str): + def tariff_setting(self, user, plan: str, expiry_duration): session = next(get_db_session()) try: - user = session.query(User).filter(User.telegram_id == telegram_id).first() - if user: - server = ( + server = ( session.query(VPNServer) .filter(VPNServer.current_users < VPNServer.max_users) .order_by(VPNServer.current_users.asc()) - .first()) - current_plan = config['subscription_templates'].get(plan) - expiry_ = datetime.now() + timedelta(days=current_plan['expiry_duration']) - new_subscription = Subscription(user_id = user.id,vpn_server_id = server.id,plan = plan,expiry_date = expiry_) - session.add(new_subscription) - session.commit() + .first() + ) + + if server is None: + self.logger.error("Нет доступных VPN серверов.") + return + + expiry_ = datetime.now() + timedelta(days=expiry_duration) + new_subscription = Subscription(user_id=user.id, vpn_server_id=server.id, plan=plan, expiry_date=expiry_) + session.add(new_subscription) + session.commit() except Exception as e: - self.logger.error(f"Чё то ошибка в установке тарифа: {e}") + self.logger.error(f"Ошибка в установке тарифа: {e}") finally: session.close() + def create_uri(self,telegram_id,): session = next(get_db_session()) try: