redesign/bug fixes/admin trial

This commit is contained in:
Vladless
2024-11-13 03:59:34 +03:00
parent 9731e87ded
commit c01c888f0e
15 changed files with 232 additions and 120 deletions
+9 -1
View File
@@ -1,6 +1,8 @@
import py3xui
from loguru import logger
from config import TOTAL_GB
async def add_client(
xui,
@@ -64,9 +66,14 @@ 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} ГБ")
await xui.client.update(client.id, client)
logger.info(
f"Ключ клиента {client.email} успешно продлён до {new_expiry_time}."
@@ -76,6 +83,7 @@ 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,
+15 -1
View File
@@ -1,5 +1,5 @@
from datetime import datetime
from loguru import logger
import asyncpg
from config import DATABASE_URL
@@ -74,6 +74,20 @@ 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
)
except Exception as e:
logger.error(f"Ошибка при установке значения триала: {e}")
finally:
await conn.close()
async def add_connection(tg_id: int, balance: float = 0.0, trial: int = 0):
conn = await asyncpg.connect(DATABASE_URL)
+1 -1
View File
@@ -3,7 +3,7 @@ from aiogram import Router, types
from aiogram.filters import Command
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from filters.admin import IsAdminFilter
from handlers.filters.admin import IsAdminFilter
from loguru import logger
from bot import bot
+4 -3
View File
@@ -3,17 +3,18 @@ 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 filters.admin import IsAdminFilter
from handlers.filters.admin import IsAdminFilter
from backup import backup_database
from bot import bot
from config import DATABASE_URL
from handlers.commands import send_message_to_all_clients
from config import DATABASE_URL, ADMIN_ID
from handlers.admin.admin_commands import send_message_to_all_clients
router = Router()
+34 -6
View File
@@ -7,12 +7,12 @@ 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 filters.admin import IsAdminFilter
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
from database import get_client_id_by_email, update_key_expiry, restore_trial
from handlers.admin.admin_panel import back_to_admin_menu
from handlers.keys.key_utils import delete_key_from_server, renew_server_key
from handlers.utils import sanitize_key_name
@@ -55,7 +55,6 @@ async def handle_tg_id_input(message: types.Message, state: FSMContext):
builder = InlineKeyboardBuilder()
# Добавляем кнопки ключей
for (email,) in key_records:
builder.row(
InlineKeyboardButton(
@@ -63,14 +62,18 @@ async def handle_tg_id_input(message: types.Message, state: FSMContext):
)
)
# Кнопка изменения баланса
builder.row(
InlineKeyboardButton(
text="📝 Изменить баланс", callback_data=f"change_balance_{tg_id}"
)
)
# Кнопка возврата
builder.row(
InlineKeyboardButton(
text="🔄 Восстановить пробник", callback_data=f"restore_trial_{tg_id}"
)
)
builder.row(
InlineKeyboardButton(text="🔙 Назад", callback_data="back_to_user_editor")
)
@@ -90,6 +93,23 @@ async def handle_tg_id_input(message: types.Message, state: FSMContext):
await conn.close()
@router.callback_query(F.data.startswith("restore_trial_"), IsAdminFilter())
async def handle_restore_trial(callback_query: types.CallbackQuery):
tg_id = int(callback_query.data.split("_")[2])
await restore_trial(tg_id)
builder = InlineKeyboardBuilder()
builder.row(
InlineKeyboardButton(text="🔙 Назад в меню администратора", callback_data="back_to_user_editor")
)
await callback_query.message.edit_text(
"✅ Триал успешно восстановлен.",
reply_markup=builder.as_markup()
)
@router.callback_query(F.data.startswith("change_balance_"), IsAdminFilter())
async def process_balance_change(callback_query: CallbackQuery, state: FSMContext):
tg_id = int(callback_query.data.split("_")[2])
@@ -239,7 +259,15 @@ async def handle_key_name_input(message: types.Message, state: FSMContext):
)
if not user_records:
await message.reply("🚫 Пользователь с указанным именем ключа не найден.")
builder = InlineKeyboardBuilder()
builder.row(
InlineKeyboardButton(text="🔙 Назад в меню администратора", callback_data="back_to_user_editor")
)
await message.reply(
"🚫 Пользователь с указанным именем ключа не найден.",
reply_markup=builder.as_markup(),
)
await state.clear()
return
+30 -9
View File
@@ -1,6 +1,7 @@
import asyncio
import uuid
from datetime import datetime, timedelta
from loguru import logger
import asyncpg
from aiogram import F, Router
@@ -9,7 +10,7 @@ from aiogram.fsm.state import State, StatesGroup
from aiogram.types import CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup, Message
from bot import bot, dp
from config import APP_URL, DATABASE_URL, PUBLIC_LINK, SERVERS
from config import DATABASE_URL, PUBLIC_LINK, SERVERS, DOWNLOAD_ANDROID, DOWNLOAD_IOS, CONNECT_ANDROID, CONNECT_IOS
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
@@ -92,6 +93,8 @@ async def select_server(callback_query: CallbackQuery, state: FSMContext):
async def confirm_create_new_key(callback_query: CallbackQuery, state: FSMContext):
tg_id = callback_query.from_user.id
logger.info(f"User {tg_id} confirmed creation of a new key.")
balance = await get_balance(tg_id)
if balance < RENEWAL_PLANS["1"]["price"]:
replenish_button = InlineKeyboardButton(
@@ -102,33 +105,38 @@ async def confirm_create_new_key(callback_query: CallbackQuery, state: FSMContex
await state.clear()
return
await callback_query.message.edit_text(
"🔑 Пожалуйста, введите имя подключаемого устройства:"
)
logger.info(f"Balance for user {tg_id} is sufficient. Asking for device name.")
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)
await callback_query.answer()
@router.message(Form.waiting_for_key_name)
async def handle_key_name_input(message: Message, state: FSMContext):
tg_id = message.from_user.id
key_name = sanitize_key_name(message.text)
logger.info(f"User {tg_id} is attempting to create a key with the name: {key_name}")
if not key_name:
await message.bot.send_message(
tg_id, "📝 Пожалуйста, назовите устройство на английском языке."
)
logger.warning(f"User {tg_id} entered an invalid key name: {key_name}")
return
conn = await asyncpg.connect(DATABASE_URL)
try:
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()
)
@@ -137,6 +145,7 @@ 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}.")
await state.set_state(Form.waiting_for_key_name)
return
finally:
@@ -149,6 +158,7 @@ async def handle_key_name_input(message: Message, state: FSMContext):
conn = await asyncpg.connect(DATABASE_URL)
try:
logger.info(f"Checking trial status for user {tg_id}.")
existing_connection = await conn.fetchrow(
"SELECT trial FROM connections WHERE tg_id = $1", tg_id
)
@@ -159,6 +169,7 @@ async def handle_key_name_input(message: Message, state: FSMContext):
if trial_status == 0:
expiry_time = current_time + timedelta(days=1, hours=3)
logger.info(f"Assigned 1-day trial to user {tg_id}.")
else:
balance = await get_balance(tg_id)
if balance < RENEWAL_PLANS["1"]["price"]:
@@ -171,32 +182,36 @@ async def handle_key_name_input(message: Message, state: FSMContext):
"💳 Недостаточно средств для создания подписки на новое устройство. Пополните баланс в личном кабинете.",
reply_markup=keyboard,
)
logger.warning(f"User {tg_id} has insufficient funds for key creation.")
await state.clear()
return
await update_balance(tg_id, -RENEWAL_PLANS["1"]["price"])
expiry_time = current_time + timedelta(days=30, hours=3)
logger.info(f"User {tg_id} balance deducted for key creation.")
expiry_timestamp = int(expiry_time.timestamp() * 1000)
public_link = f"{PUBLIC_LINK}{email}"
logger.info(f"Generated public link for the key: {public_link}")
button_profile = InlineKeyboardButton(
text="👤 Личный кабинет", callback_data="view_profile"
)
button_iphone = InlineKeyboardButton(
text="🍏 Подключить", url=f"{APP_URL}/?url=v2raytun://import/{public_link}"
text="🍏 Подключить", url=f"{CONNECT_IOS}{public_link}"
)
button_android = InlineKeyboardButton(
text="🤖 Подключить",
url=f"{APP_URL}/?url=v2raytun://import-sub?url={public_link}",
url=f"{CONNECT_ANDROID}{public_link}",
)
button_download_ios = InlineKeyboardButton(
text="🍏 Скачать", url="https://apps.apple.com/ru/app/v2raytun/id6476628951"
text="🍏 Скачать", url=DOWNLOAD_IOS
)
button_download_android = InlineKeyboardButton(
text="🤖 Скачать",
url="https://play.google.com/store/apps/details?id=com.v2raytun.android&hl=ru",
url=DOWNLOAD_ANDROID,
)
keyboard = InlineKeyboardMarkup(
@@ -211,6 +226,8 @@ async def handle_key_name_input(message: Message, state: FSMContext):
days = remaining_time.days
key_message = key_message_success(public_link, f"⏳ Осталось дней: {days} 📅")
logger.info(f"Sending key message to user {tg_id} with the public link.")
await message.bot.send_message(
tg_id, key_message, parse_mode="HTML", reply_markup=keyboard
)
@@ -230,6 +247,7 @@ async def handle_key_name_input(message: Message, state: FSMContext):
conn = await asyncpg.connect(DATABASE_URL)
try:
logger.info(f"Updating trial status for user {tg_id} in the database.")
existing_connection = await conn.fetchrow(
"SELECT * FROM connections WHERE tg_id = $1", tg_id
)
@@ -242,16 +260,19 @@ async def handle_key_name_input(message: Message, state: FSMContext):
finally:
await conn.close()
logger.info(f"Storing key for user {tg_id} in the database.")
await store_key(
tg_id, client_id, email, expiry_timestamp, public_link, "all_servers"
)
except Exception as e:
logger.error(f"Error while creating the key for user {tg_id}: {e}")
await message.bot.send_message(tg_id, f"❌ Ошибка при создании ключа: {e}")
await state.clear()
@dp.callback_query(F.data == "instructions")
async def handle_instructions(callback_query: CallbackQuery):
await send_instructions(callback_query)
+55 -23
View File
@@ -9,7 +9,7 @@ from aiogram.types import BufferedInputFile
from loguru import logger
from bot import bot
from config import APP_URL, DATABASE_URL, PUBLIC_LINK, SERVERS
from config import DATABASE_URL, PUBLIC_LINK, SERVERS, DOWNLOAD_ANDROID, DOWNLOAD_IOS, CONNECT_ANDROID, CONNECT_IOS
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
@@ -56,16 +56,32 @@ async def process_callback_view_keys(callback_query: types.CallbackQuery):
"<i>👆 Выберите устройство для управления подпиской:</i>"
)
await bot.delete_message(
chat_id=tg_id, message_id=callback_query.message.message_id
)
image_path = os.path.join(os.path.dirname(__file__), "pic_keys.jpg")
try:
await bot.delete_message(
chat_id=tg_id, message_id=callback_query.message.message_id
)
except Exception as e:
logger.error(f"Ошибка при удалении сообщения: {e}")
if os.path.isfile(image_path):
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"),
caption=response_message,
parse_mode="HTML",
reply_markup=inline_keyboard,
)
else:
await bot.send_message(
chat_id=tg_id,
text=response_message,
reply_markup=inline_keyboard,
parse_mode="HTML",
)
await bot.send_message(
chat_id=tg_id,
text=response_message,
reply_markup=inline_keyboard,
parse_mode="HTML",
)
else:
response_message = NO_KEYS
create_key_button = types.InlineKeyboardButton(
@@ -79,16 +95,31 @@ async def process_callback_view_keys(callback_query: types.CallbackQuery):
inline_keyboard=[[create_key_button], [back_button]]
)
await bot.delete_message(
chat_id=tg_id, message_id=callback_query.message.message_id
)
try:
await bot.delete_message(
chat_id=tg_id, message_id=callback_query.message.message_id
)
except Exception as e:
logger.error(f"Ошибка при удалении сообщения: {e}")
await bot.send_message(
chat_id=tg_id,
text=response_message,
reply_markup=keyboard,
parse_mode="HTML",
)
image_path = os.path.join(os.path.dirname(__file__), "pic_keys.jpg")
if os.path.isfile(image_path):
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"),
caption=response_message,
parse_mode="HTML",
reply_markup=keyboard,
)
else:
await bot.send_message(
chat_id=tg_id,
text=response_message,
reply_markup=keyboard,
parse_mode="HTML",
)
finally:
await conn.close()
@@ -99,6 +130,7 @@ 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
@@ -154,19 +186,19 @@ async def process_callback_view_key(callback_query: types.CallbackQuery):
download_android_button = types.InlineKeyboardButton(
text="🤖 Скачать",
url="https://play.google.com/store/apps/details?id=com.v2raytun.android&hl=ru",
url=DOWNLOAD_ANDROID,
)
download_iphone_button = types.InlineKeyboardButton(
text="🍏 Скачать",
url="https://apps.apple.com/ru/app/v2raytun/id6476628951",
url=DOWNLOAD_IOS,
)
connect_iphone_button = types.InlineKeyboardButton(
text="🍏 Подключить", url=f"{APP_URL}/?url=v2raytun://import/{key}"
text="🍏 Подключить", url=f"{CONNECT_IOS}{key}"
)
connect_android_button = types.InlineKeyboardButton(
text="🤖 Подключить",
url=f"{APP_URL}/?url=v2raytun://import-sub?url={key}",
url=f"{CONNECT_ANDROID}{key}",
)
renew_button = types.InlineKeyboardButton(
Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

+26 -46
View File
@@ -217,13 +217,7 @@ async def notify_24h_keys(
async def handle_expired_keys(bot: Bot, conn: asyncpg.Connection, current_time: float):
logger.info("Проверка истекших ключей...")
current_time = datetime.utcnow().timestamp() * 1000
adjusted_current_time = current_time + (3 * 60 * 60 * 1000)
logger.info(
f"Текущее время: {current_time}, Скорректированное текущее время: {adjusted_current_time}"
)
adjusted_current_time = current_time + (3 * 60 * 60 * 1000)
expiring_keys = await conn.fetch(
"""
SELECT tg_id, client_id, expiry_time, email FROM keys
@@ -231,7 +225,6 @@ async def handle_expired_keys(bot: Bot, conn: asyncpg.Connection, current_time:
""",
adjusted_current_time,
)
logger.info(f"Найдено {len(expiring_keys)} истекающих ключей.")
for record in expiring_keys:
@@ -239,17 +232,17 @@ async def handle_expired_keys(bot: Bot, conn: asyncpg.Connection, current_time:
client_id = record["client_id"]
email = record["email"]
balance = await get_balance(tg_id)
expiry_time = record["expiry_time"]
expiry_date = datetime.utcfromtimestamp(expiry_time / 1000)
current_date = datetime.utcnow()
time_left = expiry_date - current_date
logger.info(
f"Время истечения ключа: {expiry_time} (дата: {expiry_date}), Текущее время: {current_date}, Оставшееся время: {time_left}"
)
message_expired = (
"❌ Ваша подписка {email} истекла и была удалена!\n\n"
f"❌ Ваша подписка {email} истекла и была удалена!\n\n"
"🔍 Перейдите в профиль для создания нового ключа.\n"
"💡 Не откладывайте подключение VPN!"
)
@@ -265,9 +258,6 @@ async def handle_expired_keys(bot: Bot, conn: asyncpg.Connection, current_time:
(datetime.utcnow() + timedelta(days=30)).timestamp() * 1000
)
await update_key_expiry(client_id, new_expiry_time)
logger.info(
f"Ключ для клиента {tg_id} продлен до {datetime.utcfromtimestamp(new_expiry_time / 1000).strftime('%Y-%m-%d %H:%M:%S')}."
)
all_success = True
for server_id in SERVERS:
@@ -281,48 +271,38 @@ 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
)
logger.info(
f"Ключ для пользователя {tg_id} успешно продлен на месяц на всех серверах."
)
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 delete_key(client_id)
for server_id in SERVERS:
xui = AsyncApi(
SERVERS[server_id]["API_URL"],
username=ADMIN_USERNAME,
password=ADMIN_PASSWORD,
)
success = await delete_client(xui, email, client_id)
if success:
logger.info(
f"Ключ для клиента {tg_id} успешно удален с сервера {server_id}."
)
else:
logger.error(
f"Не удалось удалить ключ для клиента {tg_id} на сервере {server_id}."
)
await bot.send_message(tg_id, message_expired, reply_markup=keyboard)
except Exception as e:
logger.error(f"Ошибка при удалении ключа для клиента {tg_id}: {e}")
if "chat not found" in str(e):
logger.warning(f"Чат для клиента {tg_id} не найден. Пропуск отправки сообщения.")
await delete_key(client_id)
for server_id in SERVERS:
xui = AsyncApi(
SERVERS[server_id]["API_URL"],
username=ADMIN_USERNAME,
password=ADMIN_PASSWORD,
)
success = await delete_client(xui, email, client_id)
if success:
logger.info(f"Ключ для клиента {tg_id} успешно удален с сервера {server_id}.")
else:
logger.error(f"Не удалось удалить ключ для клиента {tg_id} на сервере {server_id}.")
except Exception as e:
logger.error(f"Ошибка при обработке ключа для клиента {tg_id}: {e}")
await asyncio.sleep(1)
+2 -1
View File
@@ -11,7 +11,8 @@ from aiogram.fsm.state import State, StatesGroup
from aiogram.types import InlineKeyboardButton
from aiogram.utils.keyboard import InlineKeyboardBuilder
from aiohttp import web
from telegram import InlineKeyboardMarkup
from aiogram.types import InlineKeyboardMarkup
from bot import bot
from config import FREEKASSA_API_KEY, FREEKASSA_SHOP_ID
+2 -1
View File
@@ -4,7 +4,8 @@ from aiogram.fsm.state import State, StatesGroup
from aiogram.types import InlineKeyboardButton
from aiogram.utils.keyboard import InlineKeyboardBuilder
from loguru import logger
from telegram import LabeledPrice
from aiogram.types import LabeledPrice
from bot import bot
from config import RUB_TO_XTR
+19 -18
View File
@@ -63,25 +63,25 @@ async def process_callback_pay_yookassa(
builder = InlineKeyboardBuilder()
for i in range(0, len(PAYMENT_OPTIONS), 2):
if i + 1 < len(PAYMENT_OPTIONS):
builder.row(
InlineKeyboardButton(
text=PAYMENT_OPTIONS[i]["text"],
callback_data=PAYMENT_OPTIONS[i]["callback_data"],
),
InlineKeyboardButton(
text=PAYMENT_OPTIONS[i + 1]["text"],
callback_data=PAYMENT_OPTIONS[i + 1]["callback_data"],
),
)
else:
builder.row(
InlineKeyboardButton(
text=PAYMENT_OPTIONS[i]["text"],
callback_data=PAYMENT_OPTIONS[i]["callback_data"],
)
for i in range(0, 4, 2):
builder.row(
InlineKeyboardButton(
text=PAYMENT_OPTIONS[i]["text"],
callback_data=PAYMENT_OPTIONS[i]["callback_data"],
),
InlineKeyboardButton(
text=PAYMENT_OPTIONS[i + 1]["text"],
callback_data=PAYMENT_OPTIONS[i + 1]["callback_data"],
),
)
for i in range(4, len(PAYMENT_OPTIONS)):
builder.row(
InlineKeyboardButton(
text=PAYMENT_OPTIONS[i]["text"],
callback_data=PAYMENT_OPTIONS[i]["callback_data"],
)
)
key_count = await get_key_count(tg_id)
@@ -107,6 +107,7 @@ 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
Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

+32 -7
View File
@@ -92,23 +92,48 @@ async def invite_handler(callback_query: types.CallbackQuery):
invite_message = invite_message_send(referral_link, referral_stats)
image_path = os.path.join(os.path.dirname(__file__), "pic_invite.jpg")
builder = InlineKeyboardBuilder()
builder.row(
InlineKeyboardButton(text="⬅️ Вернуться в профиль", callback_data="view_profile")
)
await callback_query.message.delete()
try:
await callback_query.message.delete()
except Exception as e:
logger.error(f"Ошибка при удалении сообщения: {e}")
await bot.send_message(
chat_id=chat_id,
text=invite_message,
parse_mode="HTML",
reply_markup=builder.as_markup(),
)
try:
if os.path.isfile(image_path):
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"),
caption=invite_message,
parse_mode="HTML",
reply_markup=builder.as_markup(),
)
else:
await bot.send_message(
chat_id=chat_id,
text=invite_message,
parse_mode="HTML",
reply_markup=builder.as_markup(),
)
except Exception as e:
await bot.send_message(
chat_id=chat_id,
text=f"❗️ Не удалось отправить сообщение. Техническая ошибка: {e}",
parse_mode="HTML",
reply_markup=builder.as_markup(),
)
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)
+3 -3
View File
@@ -7,7 +7,7 @@ annotated-types==0.7.0
async-timeout==4.0.3
asyncpg==0.30.0
attrs==24.2.0
certifi==2024.8.30
certifi
charset-normalizer==3.4.0
Deprecated==1.2.14
distro==1.9.0
@@ -17,8 +17,8 @@ magic-filter==1.0.12
multidict==6.1.0
netaddr==1.3.0
propcache==0.2.0
pydantic==2.9.2
pydantic_core==2.23.4
pydantic
pydantic_core
requests==2.32.3
typing_extensions==4.12.2
urllib3==2.2.3