Add crypto(beta), fix import, fix requirements.txt
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
from aiogram import Bot, Dispatcher, Router
|
||||
from aiogram.fsm.storage.memory import MemoryStorage
|
||||
|
||||
from config import API_TOKEN, FREEKASSA_ENABLE, YOOKASSA_ENABLE
|
||||
from middlewares.admin import AdminMiddleware
|
||||
from config import API_TOKEN, CRYPTO_BOT_ENABLE, FREEKASSA_ENABLE, YOOKASSA_ENABLE
|
||||
from middlewares.logging import UserActivityMiddleware
|
||||
|
||||
bot = Bot(token=API_TOKEN)
|
||||
@@ -13,7 +12,7 @@ router = Router()
|
||||
from handlers import commands, notifications, profile, start
|
||||
from handlers.admin import admin, admin_panel, user_editor
|
||||
from handlers.keys import key_management, keys
|
||||
from handlers.payment import freekassa_pay, yookassa_pay
|
||||
from handlers.payment import cryprobot_pay, freekassa_pay, yookassa_pay
|
||||
|
||||
dp.include_router(admin.router)
|
||||
dp.include_router(admin_panel.router)
|
||||
@@ -27,9 +26,9 @@ if YOOKASSA_ENABLE:
|
||||
dp.include_router(yookassa_pay.router)
|
||||
if FREEKASSA_ENABLE:
|
||||
dp.include_router(freekassa_pay.router)
|
||||
if CRYPTO_BOT_ENABLE:
|
||||
dp.include_router(cryprobot_pay.router)
|
||||
dp.include_router(notifications.router)
|
||||
|
||||
dp.message.middleware(AdminMiddleware())
|
||||
dp.callback_query.middleware(AdminMiddleware())
|
||||
dp.message.middleware(UserActivityMiddleware())
|
||||
dp.callback_query.middleware(UserActivityMiddleware())
|
||||
|
||||
+17
-17
@@ -1,27 +1,27 @@
|
||||
from aiogram import Router, types
|
||||
from aiogram.filters import Command
|
||||
from filters.admin import IsAdminFilter
|
||||
|
||||
from database import add_balance_to_client, check_connection_exists
|
||||
|
||||
router = Router()
|
||||
|
||||
|
||||
@router.message(Command("add_balance"))
|
||||
async def cmd_add_balance(message: types.Message, is_admin: bool):
|
||||
if is_admin:
|
||||
try:
|
||||
_, client_id, amount = message.text.split()
|
||||
amount = float(amount)
|
||||
@router.message(Command("add_balance"), IsAdminFilter())
|
||||
async def cmd_add_balance(message: types.Message):
|
||||
try:
|
||||
_, client_id, amount = message.text.split()
|
||||
amount = float(amount)
|
||||
|
||||
if not await check_connection_exists(int(client_id)):
|
||||
await message.reply(f"Клиент с ID {client_id} не найден.")
|
||||
return
|
||||
if not await check_connection_exists(int(client_id)):
|
||||
await message.reply(f"Клиент с ID {client_id} не найден.")
|
||||
return
|
||||
|
||||
await add_balance_to_client(int(client_id), amount)
|
||||
await message.reply(f"Баланс клиента {client_id} увеличен на {amount} у.е.")
|
||||
except ValueError:
|
||||
await message.reply(
|
||||
"Пожалуйста, используйте формат: /add_balance <client_id> <amount>"
|
||||
)
|
||||
except Exception as e:
|
||||
await message.reply(f"Произошла ошибка: {e}")
|
||||
await add_balance_to_client(int(client_id), amount)
|
||||
await message.reply(f"Баланс клиента {client_id} увеличен на {amount} у.е.")
|
||||
except ValueError:
|
||||
await message.reply(
|
||||
"Пожалуйста, используйте формат: /add_balance <client_id> <amount>"
|
||||
)
|
||||
except Exception as e:
|
||||
await message.reply(f"Произошла ошибка: {e}")
|
||||
|
||||
+122
-140
@@ -8,6 +8,7 @@ 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 backup import backup_database
|
||||
from bot import bot
|
||||
@@ -22,162 +23,143 @@ class UserEditorState(StatesGroup):
|
||||
displaying_user_info = State()
|
||||
|
||||
|
||||
@router.message(Command("admin"))
|
||||
async def handle_admin_command(message: types.Message, is_admin: bool):
|
||||
if is_admin:
|
||||
@router.message(Command("admin"), IsAdminFilter())
|
||||
async def handle_admin_command(message: types.Message):
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text="Статистика пользователей", callback_data="user_stats"
|
||||
)
|
||||
)
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="Редактор пользователей", callback_data="user_editor")
|
||||
)
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text="Отправить сообщение всем клиентам", callback_data="send_to_alls"
|
||||
)
|
||||
)
|
||||
builder.row(InlineKeyboardButton(text="Создать бэкап", callback_data="backups"))
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="Перезапустить бота", callback_data="restart_bot")
|
||||
)
|
||||
await bot.send_message(
|
||||
message.chat.id, "Панель администратора.", reply_markup=builder.as_markup()
|
||||
)
|
||||
|
||||
|
||||
@router.callback_query(F.data == "user_stats", IsAdminFilter())
|
||||
async def user_stats_menu(callback_query: CallbackQuery):
|
||||
conn = await asyncpg.connect(DATABASE_URL)
|
||||
try:
|
||||
total_users = await conn.fetchval("SELECT COUNT(*) FROM connections")
|
||||
total_keys = await conn.fetchval("SELECT COUNT(*) FROM keys")
|
||||
total_referrals = await conn.fetchval("SELECT COUNT(*) FROM referrals")
|
||||
|
||||
active_keys = await conn.fetchval(
|
||||
"SELECT COUNT(*) FROM keys WHERE expiry_time > $1",
|
||||
int(datetime.utcnow().timestamp() * 1000),
|
||||
)
|
||||
expired_keys = total_keys - active_keys
|
||||
|
||||
stats_message = (
|
||||
f"🔹 <b>Общая статистика пользователей:</b>\n"
|
||||
f"• Всего пользователей: <b>{total_users}</b>\n"
|
||||
f"• Всего ключей: <b>{total_keys}</b>\n"
|
||||
f"• Всего рефералов: <b>{total_referrals}</b>\n"
|
||||
f"• Активные ключи: <b>{active_keys}</b>\n"
|
||||
f"• Истекшие ключи: <b>{expired_keys}</b>"
|
||||
)
|
||||
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text="Статистика пользователей", callback_data="user_stats"
|
||||
)
|
||||
)
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text="Редактор пользователей", callback_data="user_editor"
|
||||
)
|
||||
)
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text="Отправить сообщение всем клиентам", callback_data="send_to_alls"
|
||||
)
|
||||
)
|
||||
builder.row(InlineKeyboardButton(text="Создать бэкап", callback_data="backups"))
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="Перезапустить бота", callback_data="restart_bot")
|
||||
)
|
||||
await bot.send_message(
|
||||
message.chat.id, "Панель администратора.", reply_markup=builder.as_markup()
|
||||
)
|
||||
else:
|
||||
await bot.send_message(message.chat.id, "У вас нет доступа к этой команде.")
|
||||
|
||||
|
||||
@router.callback_query(F.data == "user_stats")
|
||||
async def user_stats_menu(callback_query: CallbackQuery, is_admin: bool):
|
||||
if is_admin:
|
||||
conn = await asyncpg.connect(DATABASE_URL)
|
||||
try:
|
||||
total_users = await conn.fetchval("SELECT COUNT(*) FROM connections")
|
||||
total_keys = await conn.fetchval("SELECT COUNT(*) FROM keys")
|
||||
total_referrals = await conn.fetchval("SELECT COUNT(*) FROM referrals")
|
||||
|
||||
active_keys = await conn.fetchval(
|
||||
"SELECT COUNT(*) FROM keys WHERE expiry_time > $1",
|
||||
int(datetime.utcnow().timestamp() * 1000),
|
||||
)
|
||||
expired_keys = total_keys - active_keys
|
||||
|
||||
stats_message = (
|
||||
f"🔹 <b>Общая статистика пользователей:</b>\n"
|
||||
f"• Всего пользователей: <b>{total_users}</b>\n"
|
||||
f"• Всего ключей: <b>{total_keys}</b>\n"
|
||||
f"• Всего рефералов: <b>{total_referrals}</b>\n"
|
||||
f"• Активные ключи: <b>{active_keys}</b>\n"
|
||||
f"• Истекшие ключи: <b>{expired_keys}</b>"
|
||||
)
|
||||
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="Назад", callback_data="back_to_admin_menu")
|
||||
)
|
||||
|
||||
await callback_query.message.edit_text(
|
||||
stats_message, reply_markup=builder.as_markup(), parse_mode="HTML"
|
||||
)
|
||||
finally:
|
||||
await conn.close()
|
||||
await callback_query.answer()
|
||||
|
||||
|
||||
@router.callback_query(F.data == "send_to_alls")
|
||||
async def handle_send_to_all(
|
||||
callback_query: CallbackQuery, state: FSMContext, is_admin: bool
|
||||
):
|
||||
if is_admin:
|
||||
await send_message_to_all_clients(
|
||||
callback_query.message, state, from_panel=True
|
||||
)
|
||||
await callback_query.answer()
|
||||
|
||||
|
||||
@router.callback_query(F.data == "backups")
|
||||
async def handle_backup(message: Message, is_admin: bool):
|
||||
if is_admin:
|
||||
await message.answer("Запускаю бэкап базы данных...")
|
||||
await backup_database()
|
||||
await message.answer("Бэкап завершен и отправлен админу.")
|
||||
|
||||
|
||||
@router.callback_query(F.data == "restart_bot")
|
||||
async def handle_restart(callback_query: CallbackQuery, is_admin: bool):
|
||||
if is_admin:
|
||||
try:
|
||||
subprocess.run(
|
||||
["sudo", "systemctl", "restart", "bot.service"],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
await callback_query.message.answer("Бот успешно перезапущен.")
|
||||
except subprocess.CalledProcessError as e:
|
||||
await callback_query.message.answer(
|
||||
f"Бот будет перезапущен через 30 секунд {e.stderr}"
|
||||
)
|
||||
|
||||
|
||||
@router.callback_query(F.data == "user_editor")
|
||||
async def user_editor_menu(callback_query: CallbackQuery, is_admin: bool):
|
||||
if is_admin:
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text="Поиск по имени ключа", callback_data="search_by_key_name"
|
||||
)
|
||||
)
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="Поиск по tg_id", callback_data="search_by_tg_id")
|
||||
)
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="Назад", callback_data="back_to_admin_menu")
|
||||
)
|
||||
|
||||
await callback_query.message.edit_text(
|
||||
"Выберите метод поиска:", reply_markup=builder.as_markup()
|
||||
stats_message, reply_markup=builder.as_markup(), parse_mode="HTML"
|
||||
)
|
||||
finally:
|
||||
await conn.close()
|
||||
await callback_query.answer()
|
||||
|
||||
|
||||
@router.callback_query(F.data == "send_to_alls", IsAdminFilter())
|
||||
async def handle_send_to_all(callback_query: CallbackQuery, state: FSMContext):
|
||||
await send_message_to_all_clients(callback_query.message, state, from_panel=True)
|
||||
await callback_query.answer()
|
||||
|
||||
|
||||
@router.callback_query(F.data == "backups", IsAdminFilter())
|
||||
async def handle_backup(message: Message):
|
||||
await message.answer("Запускаю бэкап базы данных...")
|
||||
await backup_database()
|
||||
await message.answer("Бэкап завершен и отправлен админу.")
|
||||
|
||||
|
||||
@router.callback_query(F.data == "restart_bot", IsAdminFilter)
|
||||
async def handle_restart(callback_query: CallbackQuery):
|
||||
try:
|
||||
subprocess.run(
|
||||
["sudo", "systemctl", "restart", "bot.service"],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
await callback_query.message.answer("Бот успешно перезапущен.")
|
||||
except subprocess.CalledProcessError as e:
|
||||
await callback_query.message.answer(
|
||||
f"Бот будет перезапущен через 30 секунд {e.stderr}"
|
||||
)
|
||||
|
||||
|
||||
@router.callback_query(F.data == "back_to_admin_menu")
|
||||
async def back_to_admin_menu(callback_query: CallbackQuery, is_admin: bool):
|
||||
@router.callback_query(F.data == "user_editor", IsAdminFilter())
|
||||
async def user_editor_menu(callback_query: CallbackQuery):
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text="Поиск по имени ключа", callback_data="search_by_key_name"
|
||||
)
|
||||
)
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="Поиск по tg_id", callback_data="search_by_tg_id")
|
||||
)
|
||||
builder.row(InlineKeyboardButton(text="Назад", callback_data="back_to_admin_menu"))
|
||||
await callback_query.message.edit_text(
|
||||
"Выберите метод поиска:", reply_markup=builder.as_markup()
|
||||
)
|
||||
|
||||
|
||||
@router.callback_query(F.data == "back_to_admin_menu", IsAdminFilter())
|
||||
async def back_to_admin_menu(callback_query: CallbackQuery):
|
||||
try:
|
||||
await callback_query.message.delete()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
tg_id = callback_query.from_user.id
|
||||
if is_admin:
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text="Статистика пользователей", callback_data="user_stats"
|
||||
)
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text="Статистика пользователей", callback_data="user_stats"
|
||||
)
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text="Редактор пользователей", callback_data="user_editor"
|
||||
)
|
||||
)
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text="Отправить сообщение всем клиентам",
|
||||
callback_data="send_to_alls",
|
||||
)
|
||||
)
|
||||
builder.row(InlineKeyboardButton(text="Создать бэкап", callback_data="backups"))
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="Перезапустить бота", callback_data="restart_bot")
|
||||
)
|
||||
await bot.send_message(
|
||||
tg_id, "Панель администратора", reply_markup=builder.as_markup()
|
||||
)
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="Редактор пользователей", callback_data="user_editor")
|
||||
)
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text="Отправить сообщение всем клиентам",
|
||||
callback_data="send_to_alls",
|
||||
)
|
||||
)
|
||||
builder.row(InlineKeyboardButton(text="Создать бэкап", callback_data="backups"))
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="Перезапустить бота", callback_data="restart_bot")
|
||||
)
|
||||
await bot.send_message(
|
||||
tg_id, "Панель администратора", reply_markup=builder.as_markup()
|
||||
)
|
||||
|
||||
|
||||
async def handle_error(tg_id, callback_query, message):
|
||||
|
||||
+67
-70
@@ -4,6 +4,7 @@ from aiogram.filters import Command
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.fsm.state import State, StatesGroup
|
||||
from aiogram.types import Message
|
||||
from filters.admin import IsAdminFilter
|
||||
from loguru import logger
|
||||
|
||||
from bot import bot
|
||||
@@ -25,14 +26,13 @@ class Form(StatesGroup):
|
||||
waiting_for_message = State()
|
||||
|
||||
|
||||
@router.message(Command("backup"))
|
||||
async def backup_command(message: Message, is_admin: bool):
|
||||
if is_admin:
|
||||
from backup import backup_database
|
||||
@router.message(Command("backup"), IsAdminFilter())
|
||||
async def backup_command(message: Message):
|
||||
from backup import backup_database
|
||||
|
||||
await message.answer("Запускаю бэкап базы данных...")
|
||||
await backup_database()
|
||||
await message.answer("Бэкап завершен и отправлен админу.")
|
||||
await message.answer("Запускаю бэкап базы данных...")
|
||||
await backup_database()
|
||||
await message.answer("Бэкап завершен и отправлен админу.")
|
||||
|
||||
|
||||
@router.message(Command("start"))
|
||||
@@ -40,7 +40,7 @@ async def handle_start(message: types.Message, state: FSMContext):
|
||||
await start_command(message)
|
||||
|
||||
|
||||
@router.message(Command("add_balance"))
|
||||
@router.message(Command("add_balance"), IsAdminFilter())
|
||||
async def handle_add_balance(message: types.Message, state: FSMContext):
|
||||
await cmd_add_balance(message)
|
||||
|
||||
@@ -50,56 +50,53 @@ async def handle_menu(message: types.Message, state: FSMContext):
|
||||
await start_command(message)
|
||||
|
||||
|
||||
@router.message(Command("send_trial"))
|
||||
async def handle_send_trial_command(
|
||||
message: types.Message, state: FSMContext, is_admin: bool
|
||||
):
|
||||
if is_admin:
|
||||
@router.message(Command("send_trial"), IsAdminFilter())
|
||||
async def handle_send_trial_command(message: types.Message, state: FSMContext):
|
||||
try:
|
||||
conn = await asyncpg.connect(DATABASE_URL)
|
||||
try:
|
||||
conn = await asyncpg.connect(DATABASE_URL)
|
||||
try:
|
||||
records = await conn.fetch(
|
||||
"""
|
||||
SELECT tg_id FROM connections WHERE trial = 0
|
||||
records = await conn.fetch(
|
||||
"""
|
||||
SELECT tg_id FROM connections WHERE trial = 0
|
||||
"""
|
||||
)
|
||||
|
||||
if records:
|
||||
for record in records:
|
||||
tg_id = record["tg_id"]
|
||||
trial_message = TRIAL
|
||||
try:
|
||||
await bot.send_message(chat_id=tg_id, text=trial_message)
|
||||
except Exception as e:
|
||||
if "Forbidden: bot was blocked by the user" in str(e):
|
||||
logger.info(
|
||||
f"Бот заблокирован пользователем с tg_id: {tg_id}"
|
||||
)
|
||||
else:
|
||||
logger.error(
|
||||
f"Ошибка при отправке сообщения пользователю {tg_id}: {e}"
|
||||
)
|
||||
|
||||
await message.answer(
|
||||
"Сообщения о пробном периоде отправлены всем пользователям с не использованным ключом."
|
||||
)
|
||||
else:
|
||||
await message.answer(
|
||||
"Нет пользователей с не использованными пробными ключами."
|
||||
)
|
||||
|
||||
if records:
|
||||
for record in records:
|
||||
tg_id = record["tg_id"]
|
||||
trial_message = TRIAL
|
||||
try:
|
||||
await bot.send_message(chat_id=tg_id, text=trial_message)
|
||||
except Exception as e:
|
||||
if "Forbidden: bot was blocked by the user" in str(e):
|
||||
logger.info(
|
||||
f"Бот заблокирован пользователем с tg_id: {tg_id}"
|
||||
)
|
||||
else:
|
||||
logger.error(
|
||||
f"Ошибка при отправке сообщения пользователю {tg_id}: {e}"
|
||||
)
|
||||
finally:
|
||||
await conn.close()
|
||||
|
||||
await message.answer(
|
||||
"Сообщения о пробном периоде отправлены всем пользователям с не использованным ключом."
|
||||
)
|
||||
else:
|
||||
await message.answer(
|
||||
"Нет пользователей с не использованными пробными ключами."
|
||||
)
|
||||
|
||||
finally:
|
||||
await conn.close()
|
||||
|
||||
except Exception as e:
|
||||
await message.answer(f"Ошибка при отправке сообщений: {e}")
|
||||
except Exception as e:
|
||||
await message.answer(f"Ошибка при отправке сообщений: {e}")
|
||||
|
||||
|
||||
@router.message(Command("send_to_all"))
|
||||
@router.message(Command("send_to_all"), IsAdminFilter())
|
||||
async def send_message_to_all_clients(
|
||||
message: types.Message, state: FSMContext, is_admin: bool, from_panel=False
|
||||
message: types.Message, state: FSMContext, from_panel=False
|
||||
):
|
||||
if from_panel and is_admin:
|
||||
if from_panel:
|
||||
|
||||
await message.answer(
|
||||
"Введите текст сообщения, который вы хотите отправить всем клиентам:"
|
||||
@@ -107,32 +104,32 @@ async def send_message_to_all_clients(
|
||||
await state.set_state(Form.waiting_for_message)
|
||||
|
||||
|
||||
@router.message(Form.waiting_for_message)
|
||||
@router.message(Form.waiting_for_message, IsAdminFilter())
|
||||
async def process_message_to_all(
|
||||
message: types.Message, state: FSMContext, is_admin: bool
|
||||
message: types.Message,
|
||||
state: FSMContext,
|
||||
):
|
||||
if is_admin:
|
||||
text_message = message.text
|
||||
text_message = message.text
|
||||
|
||||
try:
|
||||
conn = await asyncpg.connect(DATABASE_URL)
|
||||
tg_ids = await conn.fetch("SELECT tg_id FROM connections")
|
||||
try:
|
||||
conn = await asyncpg.connect(DATABASE_URL)
|
||||
tg_ids = await conn.fetch("SELECT tg_id FROM connections")
|
||||
|
||||
for record in tg_ids:
|
||||
tg_id = record["tg_id"]
|
||||
try:
|
||||
await bot.send_message(chat_id=tg_id, text=text_message)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"Ошибка при отправке сообщения пользователю {tg_id}: {e}. Пропускаем этого пользователя."
|
||||
)
|
||||
for record in tg_ids:
|
||||
tg_id = record["tg_id"]
|
||||
try:
|
||||
await bot.send_message(chat_id=tg_id, text=text_message)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"Ошибка при отправке сообщения пользователю {tg_id}: {e}. Пропускаем этого пользователя."
|
||||
)
|
||||
|
||||
await message.answer("Сообщение было отправлено всем клиентам.")
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при подключении к базе данных: {e}")
|
||||
await message.answer("Произошла ошибка при отправке сообщения.")
|
||||
finally:
|
||||
await conn.close()
|
||||
await message.answer("Сообщение было отправлено всем клиентам.")
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при подключении к базе данных: {e}")
|
||||
await message.answer("Произошла ошибка при отправке сообщения.")
|
||||
finally:
|
||||
await conn.close()
|
||||
|
||||
await state.clear()
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
from aiogram.filters import BaseFilter
|
||||
from aiogram.types import Message
|
||||
|
||||
from config import ADMIN_ID
|
||||
|
||||
|
||||
class IsAdminFilter(BaseFilter):
|
||||
async def __call__(self, message: Message) -> bool:
|
||||
return message.from_user.id == ADMIN_ID
|
||||
@@ -9,7 +9,7 @@ from py3xui import AsyncApi
|
||||
from client import delete_client, extend_client_key
|
||||
from config import ADMIN_PASSWORD, ADMIN_USERNAME, DATABASE_URL, SERVERS
|
||||
from database import delete_key, get_balance, update_balance, update_key_expiry
|
||||
from handlers.texts import KEY_EXPIRY_10H, KEY_EXPIRY_24H, KEY_RENEWAL_FAILED, KEY_RENEWED, RENEWAL_PLANS
|
||||
from handlers.texts import KEY_EXPIRY_10H, KEY_EXPIRY_24H, KEY_RENEWED, RENEWAL_PLANS
|
||||
|
||||
router = Router()
|
||||
|
||||
|
||||
@@ -1,13 +1,187 @@
|
||||
from aiocryptopay import AioCryptoPay, Networks
|
||||
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.utils.keyboard import InlineKeyboardBuilder
|
||||
from aiohttp import web
|
||||
from loguru import logger
|
||||
|
||||
from config import CRYPTO_BOT_ENABLE, CRYPTO_BOT_TOKEN
|
||||
from bot import bot
|
||||
from config import CRYPTO_BOT_ENABLE, CRYPTO_BOT_TOKEN, RUB_TO_USDT
|
||||
from database import add_connection, check_connection_exists, get_key_count, update_balance
|
||||
from handlers.profile import process_callback_view_profile
|
||||
from handlers.texts import PAYMENT_OPTIONS
|
||||
|
||||
router = Router()
|
||||
|
||||
if CRYPTO_BOT_ENABLE:
|
||||
crypto = AioCryptoPay(token=CRYPTO_BOT_TOKEN, network=Networks.MAIN_NET)
|
||||
|
||||
|
||||
class ReplenishBalanceState(StatesGroup):
|
||||
choosing_amount = State()
|
||||
waiting_for_payment_confirmation = State()
|
||||
entering_custom_amount = State()
|
||||
|
||||
|
||||
async def send_message_with_deletion(
|
||||
chat_id, text, reply_markup=None, state=None, message_key="last_message_id"
|
||||
):
|
||||
if state:
|
||||
try:
|
||||
state_data = await state.get_data()
|
||||
previous_message_id = state_data.get(message_key)
|
||||
|
||||
if previous_message_id:
|
||||
await bot.delete_message(
|
||||
chat_id=chat_id, message_id=previous_message_id
|
||||
)
|
||||
|
||||
sent_message = await bot.send_message(
|
||||
chat_id=chat_id, text=text, reply_markup=reply_markup
|
||||
)
|
||||
await state.update_data({message_key: sent_message.message_id})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при удалении/отправке сообщения: {e}")
|
||||
return None
|
||||
|
||||
return sent_message
|
||||
|
||||
|
||||
@router.callback_query(F.data == "replenish_balance")
|
||||
async def process_callback_replenish_balance(
|
||||
callback_query: types.CallbackQuery, state: FSMContext
|
||||
):
|
||||
tg_id = callback_query.from_user.id
|
||||
|
||||
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"],
|
||||
)
|
||||
)
|
||||
|
||||
key_count = await get_key_count(tg_id)
|
||||
|
||||
if key_count == 0:
|
||||
exists = await check_connection_exists(tg_id)
|
||||
if not exists:
|
||||
await add_connection(tg_id, balance=0.0, trial=0)
|
||||
|
||||
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="Выберите сумму пополнения:",
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
|
||||
await state.set_state(ReplenishBalanceState.choosing_amount)
|
||||
await callback_query.answer()
|
||||
|
||||
|
||||
@router.callback_query(F.data == "back_to_profile")
|
||||
async def back_to_profile_handler(
|
||||
callback_query: types.CallbackQuery, state: FSMContext
|
||||
):
|
||||
await process_callback_view_profile(callback_query, state)
|
||||
|
||||
|
||||
@router.callback_query(F.data.startswith("amount|"))
|
||||
async def process_amount_selection(
|
||||
callback_query: types.CallbackQuery, state: FSMContext
|
||||
):
|
||||
data = callback_query.data.split("|", 1)
|
||||
|
||||
if len(data) != 2:
|
||||
await send_message_with_deletion(
|
||||
callback_query.from_user.id,
|
||||
"Неверные данные для выбора суммы.",
|
||||
state=state,
|
||||
message_key="amount_error_message_id",
|
||||
)
|
||||
return
|
||||
|
||||
amount_str = data[1]
|
||||
try:
|
||||
amount = int(amount_str)
|
||||
except ValueError:
|
||||
await send_message_with_deletion(
|
||||
callback_query.from_user.id,
|
||||
"Некорректная сумма.",
|
||||
state=state,
|
||||
message_key="amount_error_message_id",
|
||||
)
|
||||
return
|
||||
|
||||
await state.update_data(amount=amount)
|
||||
await state.set_state(ReplenishBalanceState.waiting_for_payment_confirmation)
|
||||
|
||||
try:
|
||||
invoice = await crypto.create_invoice(
|
||||
asset="USDT",
|
||||
amount=str(amount // RUB_TO_USDT),
|
||||
description=f"Пополнения баланса на {amount//RUB_TO_USDT} руб",
|
||||
payload=f"{callback_query.from_user.id}:{amount//RUB_TO_USDT}",
|
||||
)
|
||||
|
||||
if hasattr(invoice, "bot_invoice_url"):
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="Пополнить", url=invoice.bot_invoice_url),
|
||||
InlineKeyboardButton(text="⬅️ Назад", callback_data="back_to_profile"),
|
||||
)
|
||||
await callback_query.message.edit_text(
|
||||
text=f"Вы выбрали пополнение на {amount//RUB_TO_USDT} рублей.",
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
else:
|
||||
await send_message_with_deletion(
|
||||
callback_query.from_user.id, "Ошибка при создании платежа.", state=state
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при создании платежа: {e}")
|
||||
await callback_query.message.answer("Произошла ошибка при создании платежа.")
|
||||
await callback_query.answer()
|
||||
|
||||
|
||||
async def send_payment_success_notification(user_id: int, amount: float):
|
||||
try:
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="Перейти в профиль", callback_data="view_profile")
|
||||
)
|
||||
await bot.send_message(
|
||||
chat_id=user_id,
|
||||
text=f"Ваш баланс успешно пополнен на {amount} рублей. Спасибо за оплату!",
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при отправке уведомления пользователю {user_id}: {e}")
|
||||
|
||||
|
||||
async def cryptobot_webhook(request):
|
||||
try:
|
||||
data = await request.json()
|
||||
@@ -16,7 +190,9 @@ async def cryptobot_webhook(request):
|
||||
await process_crypto_payment(data["payload"])
|
||||
return web.Response(status=200)
|
||||
else:
|
||||
logger.warning(f"Неподдерживаемый тип обновления: {data.get('update_type')}")
|
||||
logger.warning(
|
||||
f"Неподдерживаемый тип обновления: {data.get('update_type')}"
|
||||
)
|
||||
return web.Response(status=400)
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка обработки вебхука: {e}")
|
||||
@@ -26,7 +202,66 @@ async def cryptobot_webhook(request):
|
||||
async def process_crypto_payment(payload):
|
||||
if payload["status"] == "paid":
|
||||
custom_payload = payload["payload"]
|
||||
user_id, sub_type = custom_payload.split(":")
|
||||
# TODO
|
||||
user_id_str, amount_str = custom_payload.split(":")
|
||||
try:
|
||||
user_id = int(user_id_str)
|
||||
amount = float(amount_str)
|
||||
logger.debug(f"Payment succeeded for user_id: {user_id}, amount: {amount}")
|
||||
await update_balance(user_id, amount)
|
||||
await send_payment_success_notification(user_id, amount)
|
||||
except ValueError as e:
|
||||
logger.error(f"Ошибка конвертации user_id или amount: {e}")
|
||||
else:
|
||||
logger.warning(f"Получен неоплаченный инвойс: {payload}")
|
||||
|
||||
|
||||
@router.callback_query(F.data == "enter_custom_amount")
|
||||
async def process_enter_custom_amount(
|
||||
callback_query: types.CallbackQuery, state: FSMContext
|
||||
):
|
||||
await callback_query.message.edit_text(text="Введите сумму пополнения:")
|
||||
await state.set_state(ReplenishBalanceState.entering_custom_amount)
|
||||
await callback_query.answer()
|
||||
|
||||
|
||||
@router.message(State(ReplenishBalanceState.entering_custom_amount))
|
||||
async def process_custom_amount_input(message: types.Message, state: FSMContext):
|
||||
if message.text.isdigit():
|
||||
amount = int(message.text)
|
||||
if amount <= 0:
|
||||
await message.answer(
|
||||
"Сумма должна быть больше нуля. Пожалуйста, введите сумму еще раз:"
|
||||
)
|
||||
return
|
||||
|
||||
await state.update_data(amount=amount)
|
||||
await state.set_state(ReplenishBalanceState.waiting_for_payment_confirmation)
|
||||
try:
|
||||
invoice = await crypto.create_invoice(
|
||||
asset="USDT",
|
||||
amount=str(amount // RUB_TO_USDT),
|
||||
description=f"Пополнения баланса на {amount//RUB_TO_USDT} руб",
|
||||
payload=f"{message.from_user.id}:{amount//RUB_TO_USDT}",
|
||||
)
|
||||
|
||||
if hasattr(invoice, "bot_invoice_url"):
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="Пополнить", url=invoice.bot_invoice_url),
|
||||
InlineKeyboardButton(
|
||||
text="⬅️ Назад", callback_data="back_to_profile"
|
||||
),
|
||||
)
|
||||
await message.message.edit_text(
|
||||
text=f"Вы выбрали пополнение на {amount//RUB_TO_USDT} рублей.",
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
else:
|
||||
await send_message_with_deletion(
|
||||
message.from_user.id, "Ошибка при создании платежа.", state=state
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при создании платежа: {e}")
|
||||
await message.answer("Произошла ошибка при создании платежа.")
|
||||
else:
|
||||
await message.answer("Некорректная сумма. Пожалуйста, введите сумму еще раз:")
|
||||
|
||||
@@ -6,7 +6,8 @@ import requests
|
||||
from aiogram import F, Router, types
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.fsm.state import State, StatesGroup
|
||||
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
|
||||
from aiogram.types import InlineKeyboardButton
|
||||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||
from aiohttp import web
|
||||
from loguru import logger
|
||||
|
||||
@@ -95,16 +96,27 @@ async def process_callback_pay_freekassa(
|
||||
callback_query: types.CallbackQuery, state: FSMContext
|
||||
):
|
||||
tg_id = callback_query.from_user.id
|
||||
inline_keyboard = []
|
||||
|
||||
for payment in PAYMENT_OPTIONS:
|
||||
inline_keyboard.append(
|
||||
InlineKeyboardButton(
|
||||
text=payment.get("text"), callback_data=payment.get("callback_data")
|
||||
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"],
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
amount_keyboard = InlineKeyboardMarkup(inline_keyboard)
|
||||
|
||||
await bot.delete_message(
|
||||
chat_id=tg_id, message_id=callback_query.message.message_id
|
||||
@@ -113,7 +125,7 @@ async def process_callback_pay_freekassa(
|
||||
await bot.send_message(
|
||||
chat_id=tg_id,
|
||||
text="Выберите сумму пополнения через FreeKassa:",
|
||||
reply_markup=amount_keyboard,
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
|
||||
await state.set_state(ReplenishBalanceState.choosing_amount)
|
||||
|
||||
@@ -17,10 +17,9 @@ from handlers.texts import PAYMENT_OPTIONS
|
||||
|
||||
router = Router()
|
||||
|
||||
Configuration.account_id = YOOKASSA_SHOP_ID
|
||||
Configuration.secret_key = YOOKASSA_SECRET_KEY
|
||||
|
||||
if YOOKASSA_ENABLE:
|
||||
Configuration.account_id = YOOKASSA_SHOP_ID
|
||||
Configuration.secret_key = YOOKASSA_SECRET_KEY
|
||||
logger.debug(f"Account ID: {YOOKASSA_SHOP_ID}")
|
||||
logger.debug(f"Secret Key: {YOOKASSA_SECRET_KEY}")
|
||||
|
||||
@@ -64,39 +63,25 @@ async def process_callback_replenish_balance(
|
||||
|
||||
builder = InlineKeyboardBuilder()
|
||||
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text=PAYMENT_OPTIONS[0]["text"],
|
||||
callback_data=PAYMENT_OPTIONS[0]["callback_data"],
|
||||
),
|
||||
InlineKeyboardButton(
|
||||
text=PAYMENT_OPTIONS[1]["text"],
|
||||
callback_data=PAYMENT_OPTIONS[1]["callback_data"],
|
||||
),
|
||||
)
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text=PAYMENT_OPTIONS[2]["text"],
|
||||
callback_data=PAYMENT_OPTIONS[2]["callback_data"],
|
||||
),
|
||||
InlineKeyboardButton(
|
||||
text=PAYMENT_OPTIONS[3]["text"],
|
||||
callback_data=PAYMENT_OPTIONS[3]["callback_data"],
|
||||
),
|
||||
)
|
||||
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text=PAYMENT_OPTIONS[4]["text"],
|
||||
callback_data=PAYMENT_OPTIONS[4]["callback_data"],
|
||||
)
|
||||
)
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text=PAYMENT_OPTIONS[5]["text"],
|
||||
callback_data=PAYMENT_OPTIONS[5]["callback_data"],
|
||||
)
|
||||
)
|
||||
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"],
|
||||
)
|
||||
)
|
||||
|
||||
key_count = await get_key_count(tg_id)
|
||||
|
||||
@@ -215,20 +200,15 @@ async def process_amount_selection(
|
||||
|
||||
async def send_payment_success_notification(user_id: int, amount: float):
|
||||
try:
|
||||
profile_keyboard = InlineKeyboardMarkup(
|
||||
inline_keyboard=[
|
||||
[
|
||||
InlineKeyboardButton(
|
||||
text="Перейти в профиль", callback_data="view_profile"
|
||||
)
|
||||
]
|
||||
]
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="Перейти в профиль", callback_data="view_profile")
|
||||
)
|
||||
|
||||
await bot.send_message(
|
||||
chat_id=user_id,
|
||||
text=f"Ваш баланс успешно пополнен на {amount} рублей. Спасибо за оплату!",
|
||||
reply_markup=profile_keyboard,
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при отправке уведомления пользователю {user_id}: {e}")
|
||||
@@ -236,26 +216,19 @@ async def send_payment_success_notification(user_id: int, amount: float):
|
||||
|
||||
async def yookassa_webhook(request):
|
||||
event = await request.json()
|
||||
|
||||
logger.debug(f"Webhook event received: {event}")
|
||||
|
||||
if event["event"] == "payment.succeeded":
|
||||
user_id_str = event["object"]["metadata"]["user_id"]
|
||||
amount_str = event["object"]["amount"]["value"]
|
||||
|
||||
try:
|
||||
user_id = int(user_id_str)
|
||||
amount = float(amount_str)
|
||||
|
||||
logger.debug(f"Payment succeeded for user_id: {user_id}, amount: {amount}")
|
||||
await update_balance(user_id, amount)
|
||||
|
||||
await send_payment_success_notification(user_id, amount)
|
||||
|
||||
except ValueError as e:
|
||||
logger.error(f"Ошибка конвертации user_id или amount: {e}")
|
||||
return web.Response(status=400)
|
||||
|
||||
return web.Response(status=200)
|
||||
|
||||
|
||||
|
||||
@@ -11,9 +11,9 @@ from config import CRYPTO_BOT_ENABLE, FREEKASSA_ENABLE, SUB_PATH, WEBAPP_HOST, W
|
||||
from database import init_db
|
||||
from handlers.keys.subscriptions import handle_subscription
|
||||
from handlers.notifications import notify_expiring_keys
|
||||
from handlers.payment.cryprobot_pay import cryptobot_webhook
|
||||
from handlers.payment.freekassa_pay import freekassa_webhook
|
||||
from handlers.payment.yookassa_pay import yookassa_webhook
|
||||
from handlers.payment.cryprobot_pay import cryptobot_webhook
|
||||
|
||||
|
||||
async def periodic_notifications():
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
from typing import Any, Awaitable, Callable, Dict
|
||||
|
||||
from aiogram import BaseMiddleware
|
||||
from aiogram.types import CallbackQuery, Message, TelegramObject
|
||||
|
||||
from config import ADMIN_ID
|
||||
|
||||
|
||||
class AdminMiddleware(BaseMiddleware):
|
||||
async def __call__(
|
||||
self,
|
||||
handler: Callable[[TelegramObject, Dict[str, Any]], Awaitable[Any]],
|
||||
event: TelegramObject,
|
||||
data: Dict[str, Any],
|
||||
) -> Any:
|
||||
user_id = None
|
||||
|
||||
if isinstance(event, Message):
|
||||
user_id = event.from_user.id
|
||||
elif isinstance(event, CallbackQuery):
|
||||
user_id = event.from_user.id
|
||||
|
||||
if user_id != int(ADMIN_ID):
|
||||
data["is_admin"] = False
|
||||
else:
|
||||
data["is_admin"] = True
|
||||
|
||||
return await handler(event, data)
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
# Обработка HTTP-запросов, редирект на HTTPS
|
||||
server {
|
||||
listen 80;
|
||||
server_name example.com; # Домен проекта
|
||||
|
||||
location / {
|
||||
# Перенаправление с HTTP на HTTPS
|
||||
if ($arg_url != "") {
|
||||
return 301 $arg_url;
|
||||
}
|
||||
|
||||
return 404 "URL-аргумент отсутствует";
|
||||
}
|
||||
}
|
||||
|
||||
# Обработка HTTPS-запросов (статический сайт и прокси)
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name example.com; # Домен проекта
|
||||
|
||||
# SSL настройки
|
||||
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # Путь к SSL-сертификату
|
||||
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # Путь к приватному ключу
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf;
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
||||
|
||||
# Обработка подписок
|
||||
location /sub {
|
||||
proxy_pass http://localhost:3001;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
add_header Content-Type text/plain;
|
||||
add_header Content-Disposition inline;
|
||||
add_header Cache-Control no-store;
|
||||
add_header Pragma no-cache;
|
||||
}
|
||||
|
||||
# Статический сайт
|
||||
root /var/www/website; # Путь к статическому сайту
|
||||
index index.html; # Основной файл
|
||||
|
||||
location / {
|
||||
# Перенаправление с HTTP на HTTPS
|
||||
if ($arg_url != "") {
|
||||
return 301 $arg_url;
|
||||
}
|
||||
|
||||
return 404 "URL-аргумент отсутствует";
|
||||
}
|
||||
|
||||
# Вебхуки из main.py
|
||||
location /webhook {
|
||||
proxy_pass http://localhost:3001/webhook;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
|
||||
# Вебхук Юкассы
|
||||
location /yookassa/webhook {
|
||||
proxy_pass http://localhost:3001/yookassa/webhook;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
|
||||
# Вебхук FreeCassa
|
||||
location /freekassa/webhook {
|
||||
proxy_pass http://localhost:3001/freekassa/webhook;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
|
||||
# Вебхук CryptoBot
|
||||
location /cryptobot/webhook {
|
||||
proxy_pass http://localhost:3001/cryptobot/webhook;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -26,4 +26,5 @@ wrapt==1.16.0
|
||||
yarl==1.15.5
|
||||
yookassa==3.3.0
|
||||
loguru
|
||||
aiocryptopay
|
||||
aiocryptopay
|
||||
py3xui
|
||||
Reference in New Issue
Block a user