add temporary Remnawave API functions for user import / add UTM code validation in ads creation

This commit is contained in:
Capybara-z
2025-06-29 17:27:07 +03:00
parent 8ee133edc6
commit e7f91a971b
3 changed files with 131 additions and 5 deletions
+12 -1
View File
@@ -4,6 +4,7 @@ from aiogram.fsm.state import State, StatesGroup
from aiogram.types import CallbackQuery, Message
from sqlalchemy import delete, select, update
from sqlalchemy.ext.asyncio import AsyncSession
import re
from config import USERNAME_BOT
from database import create_tracking_source, get_tracking_source_stats
@@ -50,7 +51,8 @@ async def handle_ads_name_input(message: Message, state: FSMContext):
await state.update_data(name=name)
await state.set_state(AdminAdsState.waiting_for_new_code)
await message.answer(
f"🔗 Введите <b>код ссылки</b> для: <code>{name}</code>.",
f"🔗 Введите <b>код ссылки</b> для: <code>{name}</code>.\n\n"
f"💡 <b>Правила:</b> только латинские буквы и цифры",
reply_markup=build_cancel_input_kb(),
)
@@ -62,6 +64,15 @@ async def handle_ads_code_input(
code = message.text.strip()
data = await state.get_data()
name = data["name"]
if not re.match(r'^[a-zA-Z0-9]+$', code):
await message.answer(
"❌ Код может содержать только латинские буквы и цифры\n"
"Введите код заново:",
reply_markup=build_cancel_input_kb(),
)
return
code_with_prefix = f"utm_{code}"
try:
@@ -12,6 +12,7 @@ import os, subprocess, sys
import json
from aiogram import Bot
from panels.remnawave import RemnawaveAPI
from panels.remnawave_time import get_all_users_time, login_remnawave
from tempfile import NamedTemporaryFile
import traceback
from datetime import datetime
@@ -426,16 +427,32 @@ async def show_remnawave_clients(callback: CallbackQuery, session: AsyncSession)
return
server = servers[0]
api = RemnawaveAPI(base_url=server.api_url)
# api = RemnawaveAPI(base_url=server.api_url)
#
# if not await api.login(username=REMNAWAVE_LOGIN, password=REMNAWAVE_PASSWORD):
# await callback.message.edit_text(
# "❌ Не удалось авторизоваться на Remnawave панели.",
# reply_markup=build_back_to_db_menu(),
# )
# return
#
# users = await api.get_all_users()
# if not users:
# await callback.message.edit_text(
# "📭 На панели нет клиентов.",
# reply_markup=build_back_to_db_menu(),
# )
# return
if not await api.login(username=REMNAWAVE_LOGIN, password=REMNAWAVE_PASSWORD):
token = await login_remnawave(server.api_url, REMNAWAVE_LOGIN, REMNAWAVE_PASSWORD)
if not token:
await callback.message.edit_text(
"❌ Не удалось авторизоваться на Remnawave панели.",
reply_markup=build_back_to_db_menu(),
)
return
users = await api.get_all_users()
users = await get_all_users_time(server.api_url, REMNAWAVE_LOGIN, REMNAWAVE_PASSWORD)
if not users:
await callback.message.edit_text(
"📭 На панели нет клиентов.",
@@ -560,4 +577,4 @@ async def import_remnawave_keys(session: AsyncSession, users: list[dict], server
await session.commit()
logger.info(f"[IMPORT] Всего добавлено ключей: {added}")
return added
return added
+98
View File
@@ -0,0 +1,98 @@
import aiohttp
from typing import List, Dict, Any
from logger import logger
from config import REMNAWAVE_TOKEN_LOGIN_ENABLED, REMNAWAVE_ACCESS_TOKEN, REMNAWAVE_LOGIN, REMNAWAVE_PASSWORD
async def login_remnawave(api_url: str, username: str, password: str) -> str | None:
if REMNAWAVE_TOKEN_LOGIN_ENABLED and REMNAWAVE_ACCESS_TOKEN:
logger.info("[Remnawave API] Используется авторизация по токену")
return REMNAWAVE_ACCESS_TOKEN
async with aiohttp.ClientSession() as session:
auth_data = {
"username": username,
"password": password
}
try:
auth_response = await session.post(f"{api_url}/auth/login", json=auth_data)
if auth_response.status != 200:
logger.error(f"[Remnawave API] Ошибка HTTP статуса: {auth_response.status}")
return None
auth_result = await auth_response.json()
token = None
if auth_result.get("success") and auth_result.get("data", {}).get("token"):
token = auth_result.get("data", {}).get("token")
elif auth_result.get("response", {}).get("accessToken"):
token = auth_result.get("response", {}).get("accessToken")
elif auth_result.get("token"):
token = auth_result.get("token")
if not token:
logger.error(f"[Remnawave API] Токен не найден в ответе")
return token
except Exception as e:
logger.error(f"[Remnawave API] Ошибка при авторизации: {e}")
return None
async def get_all_users_time(api_url: str, username: str, password: str) -> List[Dict[str, Any]]:
all_users = []
page_size = 250
start = 0
token = await login_remnawave(api_url, username, password)
if not token:
logger.error("[Remnawave API] Не удалось получить токен авторизации")
return []
headers = {"Authorization": f"Bearer {token}"}
async with aiohttp.ClientSession() as session:
while True:
params = {
"size": page_size,
"start": start
}
users_endpoint = f"{api_url}/users"
users_response = await session.get(users_endpoint, params=params, headers=headers)
if users_response.status != 200:
break
users_result = await users_response.json()
if users_result.get("success") is False:
break
users_data = None
if "response" in users_result:
users_data = users_result.get("response", {})
elif "data" in users_result:
users_data = users_result.get("data", {})
else:
users_data = users_result
if not users_data:
break
users = users_data.get("users", [])
total = users_data.get("total", 0)
if not users:
break
all_users.extend(users)
start += len(users)
if len(users) < page_size or start >= total:
break
return all_users