redesign/bug fixes/admin trial

This commit is contained in:
Vladless
2024-11-13 04:01:13 +03:00
parent c01c888f0e
commit 38f02bbcb6
12 changed files with 73 additions and 56 deletions
+6 -5
View File
@@ -66,14 +66,16 @@ async def extend_client_key(xui, email: str, new_expiry_time: int, client_id: st
logger.info(
f"Обновление ключа клиента {client.email} с ID {client.id} до нового времени: {new_expiry_time}"
)
client.id = client_id
client.expiry_time = new_expiry_time
if TOTAL_GB > 0:
client.total_gb = TOTAL_GB
logger.info(f"Установлен объем трафика для клиента {client.email}: {TOTAL_GB} ГБ")
logger.info(
f"Установлен объем трафика для клиента {client.email}: {TOTAL_GB} ГБ"
)
await xui.client.update(client.id, client)
logger.info(
f"Ключ клиента {client.email} успешно продлён до {new_expiry_time}."
@@ -83,7 +85,6 @@ async def extend_client_key(xui, email: str, new_expiry_time: int, client_id: st
logger.error(f"Ошибка при обновлении клиента с email {email}: {e}")
async def delete_client(
xui,
email: str,
+4 -6
View File
@@ -1,6 +1,7 @@
from datetime import datetime
from loguru import logger
import asyncpg
from loguru import logger
from config import DATABASE_URL
@@ -74,12 +75,11 @@ async def init_db():
await conn.close()
async def restore_trial(tg_id: int):
conn = await asyncpg.connect(DATABASE_URL)
try:
await conn.execute(
"UPDATE connections SET trial = 0 WHERE tg_id = $1", tg_id
)
await conn.execute("UPDATE connections SET trial = 0 WHERE tg_id = $1", tg_id)
except Exception as e:
logger.error(f"Ошибка при установке значения триала: {e}")
@@ -87,8 +87,6 @@ async def restore_trial(tg_id: int):
await conn.close()
async def add_connection(tg_id: int, balance: float = 0.0, trial: int = 0):
conn = await asyncpg.connect(DATABASE_URL)
await conn.execute(
+1 -1
View File
@@ -3,12 +3,12 @@ from aiogram import Router, types
from aiogram.filters import Command
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from handlers.filters.admin import IsAdminFilter
from loguru import logger
from bot import bot
from config import DATABASE_URL
from database import add_balance_to_client, check_connection_exists
from handlers.filters.admin import IsAdminFilter
from handlers.texts import TRIAL
router = Router()
+2 -3
View File
@@ -3,18 +3,17 @@ from datetime import datetime
import asyncpg
from aiogram import F, Router, types
from aiogram.filters import Command
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.types import CallbackQuery, InlineKeyboardButton, Message
from aiogram.utils.keyboard import InlineKeyboardBuilder
from handlers.filters.admin import IsAdminFilter
from backup import backup_database
from bot import bot
from config import DATABASE_URL, ADMIN_ID
from config import DATABASE_URL
from handlers.admin.admin_commands import send_message_to_all_clients
from handlers.filters.admin import IsAdminFilter
router = Router()
+10 -6
View File
@@ -7,13 +7,13 @@ from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.types import CallbackQuery, InlineKeyboardButton
from aiogram.utils.keyboard import InlineKeyboardBuilder
from handlers.filters.admin import IsAdminFilter
from loguru import logger
from bot import bot
from config import DATABASE_URL, SERVERS
from database import get_client_id_by_email, update_key_expiry, restore_trial
from database import get_client_id_by_email, restore_trial, update_key_expiry
from handlers.admin.admin_panel import back_to_admin_menu
from handlers.filters.admin import IsAdminFilter
from handlers.keys.key_utils import delete_key_from_server, renew_server_key
from handlers.utils import sanitize_key_name
@@ -101,12 +101,13 @@ async def handle_restore_trial(callback_query: types.CallbackQuery):
builder = InlineKeyboardBuilder()
builder.row(
InlineKeyboardButton(text="🔙 Назад в меню администратора", callback_data="back_to_user_editor")
InlineKeyboardButton(
text="🔙 Назад в меню администратора", callback_data="back_to_user_editor"
)
)
await callback_query.message.edit_text(
"✅ Триал успешно восстановлен.",
reply_markup=builder.as_markup()
"✅ Триал успешно восстановлен.", reply_markup=builder.as_markup()
)
@@ -261,7 +262,10 @@ async def handle_key_name_input(message: types.Message, state: FSMContext):
if not user_records:
builder = InlineKeyboardBuilder()
builder.row(
InlineKeyboardButton(text="🔙 Назад в меню администратора", callback_data="back_to_user_editor")
InlineKeyboardButton(
text="🔙 Назад в меню администратора",
callback_data="back_to_user_editor",
)
)
await message.reply(
+13 -9
View File
@@ -1,16 +1,16 @@
import asyncio
import uuid
from datetime import datetime, timedelta
from loguru import logger
import asyncpg
from aiogram import F, Router
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.types import CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup, Message
from loguru import logger
from bot import bot, dp
from config import DATABASE_URL, PUBLIC_LINK, SERVERS, DOWNLOAD_ANDROID, DOWNLOAD_IOS, CONNECT_ANDROID, CONNECT_IOS
from config import CONNECT_ANDROID, CONNECT_IOS, DATABASE_URL, DOWNLOAD_ANDROID, DOWNLOAD_IOS, PUBLIC_LINK, SERVERS
from database import add_connection, get_balance, store_key, update_balance
from handlers.instructions.instructions import send_instructions
from handlers.keys.key_utils import create_key_on_server
@@ -107,13 +107,16 @@ async def confirm_create_new_key(callback_query: CallbackQuery, state: FSMContex
logger.info(f"Balance for user {tg_id} is sufficient. Asking for device name.")
await callback_query.message.edit_text("🔑 Пожалуйста, введите имя подключаемого устройства:")
await callback_query.message.edit_text(
"🔑 Пожалуйста, введите имя подключаемого устройства:"
)
await state.set_state(Form.waiting_for_key_name)
logger.info(f"State set to waiting_for_key_name for user {tg_id}")
await state.update_data(creating_new_key=True)
await callback_query.answer()
@dp.callback_query(F.data == "cancel_create_key")
async def cancel_create_key(callback_query: CallbackQuery, state: FSMContext):
await process_callback_view_profile(callback_query, state)
@@ -136,7 +139,9 @@ async def handle_key_name_input(message: Message, state: FSMContext):
conn = await asyncpg.connect(DATABASE_URL)
try:
logger.info(f"Checking if key name '{key_name}' already exists in the database.")
logger.info(
f"Checking if key name '{key_name}' already exists in the database."
)
existing_key = await conn.fetchrow(
"SELECT * FROM keys WHERE email = $1", key_name.lower()
)
@@ -145,7 +150,9 @@ async def handle_key_name_input(message: Message, state: FSMContext):
tg_id,
"❌ Упс! Это имя уже используется. Выберите другое уникальное название для ключа.",
)
logger.warning(f"Key name '{key_name}' already exists in the database for user {tg_id}.")
logger.warning(
f"Key name '{key_name}' already exists in the database for user {tg_id}."
)
await state.set_state(Form.waiting_for_key_name)
return
finally:
@@ -206,9 +213,7 @@ async def handle_key_name_input(message: Message, state: FSMContext):
url=f"{CONNECT_ANDROID}{public_link}",
)
button_download_ios = InlineKeyboardButton(
text="🍏 Скачать", url=DOWNLOAD_IOS
)
button_download_ios = InlineKeyboardButton(text="🍏 Скачать", url=DOWNLOAD_IOS)
button_download_android = InlineKeyboardButton(
text="🤖 Скачать",
url=DOWNLOAD_ANDROID,
@@ -272,7 +277,6 @@ async def handle_key_name_input(message: Message, state: FSMContext):
await state.clear()
@dp.callback_query(F.data == "instructions")
async def handle_instructions(callback_query: CallbackQuery):
await send_instructions(callback_query)
+7 -4
View File
@@ -9,7 +9,7 @@ from aiogram.types import BufferedInputFile
from loguru import logger
from bot import bot
from config import DATABASE_URL, PUBLIC_LINK, SERVERS, DOWNLOAD_ANDROID, DOWNLOAD_IOS, CONNECT_ANDROID, CONNECT_IOS
from config import CONNECT_ANDROID, CONNECT_IOS, DATABASE_URL, DOWNLOAD_ANDROID, DOWNLOAD_IOS, PUBLIC_LINK, SERVERS
from database import delete_key, get_balance, store_key, update_balance, update_key_expiry
from handlers.keys.key_utils import delete_key_from_db, delete_key_from_server, renew_server_key, update_key_on_server
from handlers.texts import INSUFFICIENT_FUNDS_MSG, KEY_NOT_FOUND_MSG, NO_KEYS, PLAN_SELECTION_MSG, RENEWAL_PLANS, SUCCESS_RENEWAL_MSG, key_message
@@ -69,7 +69,9 @@ async def process_callback_view_keys(callback_query: types.CallbackQuery):
with open(image_path, "rb") as image_file:
await bot.send_photo(
chat_id=tg_id,
photo=BufferedInputFile(image_file.read(), filename="pic_keys.jpg"),
photo=BufferedInputFile(
image_file.read(), filename="pic_keys.jpg"
),
caption=response_message,
parse_mode="HTML",
reply_markup=inline_keyboard,
@@ -108,7 +110,9 @@ async def process_callback_view_keys(callback_query: types.CallbackQuery):
with open(image_path, "rb") as image_file:
await bot.send_photo(
chat_id=tg_id,
photo=BufferedInputFile(image_file.read(), filename="pic_keys.jpg"),
photo=BufferedInputFile(
image_file.read(), filename="pic_keys.jpg"
),
caption=response_message,
parse_mode="HTML",
reply_markup=keyboard,
@@ -130,7 +134,6 @@ async def process_callback_view_keys(callback_query: types.CallbackQuery):
await callback_query.answer()
@router.callback_query(F.data.startswith("view_key|"))
async def process_callback_view_key(callback_query: types.CallbackQuery):
tg_id = callback_query.from_user.id
+23 -10
View File
@@ -217,7 +217,7 @@ async def notify_24h_keys(
async def handle_expired_keys(bot: Bot, conn: asyncpg.Connection, current_time: float):
logger.info("Проверка истекших ключей...")
adjusted_current_time = current_time + (3 * 60 * 60 * 1000)
adjusted_current_time = current_time + (3 * 60 * 60 * 1000)
expiring_keys = await conn.fetch(
"""
SELECT tg_id, client_id, expiry_time, email FROM keys
@@ -271,22 +271,32 @@ async def handle_expired_keys(bot: Bot, conn: asyncpg.Connection, current_time:
)
if not success:
all_success = False
logger.error(f"Не удалось продлить ключ для пользователя {tg_id} на сервере {server_id}.")
logger.error(
f"Не удалось продлить ключ для пользователя {tg_id} на сервере {server_id}."
)
if all_success:
try:
await bot.send_message(tg_id, KEY_RENEWED, reply_markup=keyboard)
await bot.send_message(
tg_id, KEY_RENEWED, reply_markup=keyboard
)
logger.info(f"Ключ для пользователя {tg_id} успешно продлен.")
except Exception as e:
logger.error(f"Ошибка при отправке уведомления пользователю {tg_id}: {e}")
logger.error(
f"Ошибка при отправке уведомления пользователю {tg_id}: {e}"
)
else:
try:
await bot.send_message(tg_id, message_expired, reply_markup=keyboard)
await bot.send_message(
tg_id, message_expired, reply_markup=keyboard
)
except Exception as e:
if "chat not found" in str(e):
logger.warning(f"Чат для клиента {tg_id} не найден. Пропуск отправки сообщения.")
logger.warning(
f"Чат для клиента {tg_id} не найден. Пропуск отправки сообщения."
)
await delete_key(client_id)
for server_id in SERVERS:
@@ -297,12 +307,15 @@ async def handle_expired_keys(bot: Bot, conn: asyncpg.Connection, current_time:
)
success = await delete_client(xui, email, client_id)
if success:
logger.info(f"Ключ для клиента {tg_id} успешно удален с сервера {server_id}.")
logger.info(
f"Ключ для клиента {tg_id} успешно удален с сервера {server_id}."
)
else:
logger.error(f"Не удалось удалить ключ для клиента {tg_id} на сервере {server_id}.")
logger.error(
f"Не удалось удалить ключ для клиента {tg_id} на сервере {server_id}."
)
except Exception as e:
logger.error(f"Ошибка при обработке ключа для клиента {tg_id}: {e}")
await asyncio.sleep(1)
+1 -3
View File
@@ -8,11 +8,9 @@ import requests
from aiogram import Router, types
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.types import InlineKeyboardButton
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
from aiogram.utils.keyboard import InlineKeyboardBuilder
from aiohttp import web
from aiogram.types import InlineKeyboardMarkup
from bot import bot
from config import FREEKASSA_API_KEY, FREEKASSA_SHOP_ID
+1 -3
View File
@@ -1,12 +1,10 @@
from aiogram import F, Router, types
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.types import InlineKeyboardButton
from aiogram.types import InlineKeyboardButton, LabeledPrice
from aiogram.utils.keyboard import InlineKeyboardBuilder
from loguru import logger
from aiogram.types import LabeledPrice
from bot import bot
from config import RUB_TO_XTR
from database import add_connection, check_connection_exists, get_key_count, update_balance
+2 -3
View File
@@ -63,7 +63,7 @@ async def process_callback_pay_yookassa(
builder = InlineKeyboardBuilder()
for i in range(0, 4, 2):
for i in range(0, 4, 2):
builder.row(
InlineKeyboardButton(
text=PAYMENT_OPTIONS[i]["text"],
@@ -75,7 +75,7 @@ async def process_callback_pay_yookassa(
),
)
for i in range(4, len(PAYMENT_OPTIONS)):
for i in range(4, len(PAYMENT_OPTIONS)):
builder.row(
InlineKeyboardButton(
text=PAYMENT_OPTIONS[i]["text"],
@@ -107,7 +107,6 @@ async def process_callback_pay_yookassa(
await callback_query.answer()
@router.callback_query(F.data == "back_to_profile")
async def back_to_profile_handler(
callback_query: types.CallbackQuery, state: FSMContext
+3 -3
View File
@@ -109,7 +109,9 @@ async def invite_handler(callback_query: types.CallbackQuery):
with open(image_path, "rb") as image_file:
await bot.send_photo(
chat_id=chat_id,
photo=BufferedInputFile(image_file.read(), filename="pic_invite.jpg"),
photo=BufferedInputFile(
image_file.read(), filename="pic_invite.jpg"
),
caption=invite_message,
parse_mode="HTML",
reply_markup=builder.as_markup(),
@@ -132,8 +134,6 @@ async def invite_handler(callback_query: types.CallbackQuery):
await callback_query.answer()
@router.callback_query(F.data == "view_profile")
async def view_profile_handler(callback_query: types.CallbackQuery, state: FSMContext):
await process_callback_view_profile(callback_query, state)