fix admin crypto links / fix sender button formatting

This commit is contained in:
Capybara-z
2025-11-16 01:15:15 +03:00
parent 041e1c898d
commit 1d5c80cd35
7 changed files with 95 additions and 59 deletions
+2 -12
View File
@@ -314,11 +314,6 @@ async def handle_sync_server(
sub = await remna.get_subscription_by_username(key["email"])
if sub:
new_remnawave_link = sub.get("subscriptionUrl")
if HAPP_CRYPTOLINK:
happ = sub.get("happ") or {}
new_remnawave_link = (
happ.get("cryptoLink") or happ.get("link") or new_remnawave_link
)
if new_remnawave_link:
server_result = await session.execute(
@@ -336,7 +331,7 @@ async def handle_sync_server(
email=key["email"],
client_id=key["client_id"],
tg_id=key["tg_id"],
remna_link_override=new_remnawave_link,
remna_link_override=None,
plan=key["tariff_id"],
)
@@ -544,11 +539,6 @@ async def handle_sync_cluster(
sub = await remna.get_subscription_by_username(key["email"])
if sub:
new_remnawave_link = sub.get("subscriptionUrl")
if HAPP_CRYPTOLINK:
happ = sub.get("happ") or {}
new_remnawave_link = (
happ.get("cryptoLink") or happ.get("link") or new_remnawave_link
)
if new_remnawave_link:
servers = await get_servers(session)
@@ -561,7 +551,7 @@ async def handle_sync_cluster(
email=key["email"],
client_id=key["client_id"],
tg_id=key["tg_id"],
remna_link_override=new_remnawave_link,
remna_link_override=None,
plan=key["tariff_id"],
)
+55 -7
View File
@@ -170,13 +170,24 @@ async def get_recipients(session: AsyncSession, send_to: str, cluster_name: str
return tg_ids, len(tg_ids)
def strip_html_tags(text: str) -> str:
text = re.sub(r'<tg-emoji emoji-id="[^"]*">([^<]*)</tg-emoji>', r"\1", text)
text = re.sub(r'<[^>]+>', '', text)
text = text.replace('&lt;', '<').replace('&gt;', '>').replace('&amp;', '&')
return text.strip()
def parse_message_buttons(text: str) -> tuple[str, InlineKeyboardMarkup | None]:
if "BUTTONS:" not in text:
buttons_match = re.search(r'(<[^>]+>)?\s*BUTTONS\s*:\s*(</[^>]+>)?', text, re.IGNORECASE)
if not buttons_match:
return text, None
parts = text.split("BUTTONS:", 1)
clean_text = parts[0].strip()
buttons_text = parts[1].strip()
clean_text = text[:buttons_match.start()].strip()
buttons_section = text[buttons_match.start():].strip()
buttons_text = strip_html_tags(buttons_section)
buttons_text = re.sub(r'^.*?BUTTONS\s*:\s*', '', buttons_text, flags=re.IGNORECASE).strip()
if not buttons_text:
return clean_text, None
@@ -186,9 +197,7 @@ def parse_message_buttons(text: str) -> tuple[str, InlineKeyboardMarkup | None]:
for line in button_lines:
try:
cleaned_line = re.sub(r'<tg-emoji emoji-id="[^"]*">([^<]*)</tg-emoji>', r"\1", line)
button_data = json.loads(cleaned_line)
button_data = json.loads(line)
if not isinstance(button_data, dict) or "text" not in button_data:
logger.warning(f"Неверный формат кнопки: {line}")
@@ -307,6 +316,21 @@ async def handle_message_input(message: Message, state: FSMContext, session: Asy
cluster_name = data.get("cluster_name")
_, user_count = await get_recipients(session, send_to, cluster_name)
if keyboard:
try:
keyboard_dict = keyboard.model_dump()
InlineKeyboardMarkup.model_validate(keyboard_dict)
except Exception as e:
await message.answer(
f"❌ <b>Ошибка в клавиатуре!</b>\n\n"
f"Не удалось сохранить клавиатуру из указанных кнопок.\n"
f"Ошибка: {str(e)}\n\n"
f"Пожалуйста, проверьте формат кнопок и попробуйте снова.",
reply_markup=build_admin_back_kb("sender"),
)
await state.clear()
return
await state.update_data(text=clean_text, photo=photo, keyboard=keyboard.model_dump() if keyboard else None)
await state.set_state(AdminSender.preview)
@@ -343,9 +367,33 @@ async def handle_send_confirm(callback_query: CallbackQuery, state: FSMContext,
keyboard = InlineKeyboardMarkup.model_validate(keyboard_data)
except Exception as e:
logger.error(f"Ошибка восстановления клавиатуры: {e}")
await callback_query.message.edit_text(
f"❌ <b>Ошибка восстановления клавиатуры!</b>\n\n"
f"Не удалось восстановить клавиатуру из сохраненных данных.\n"
f"Ошибка: {str(e)}\n\n"
f"Пожалуйста, создайте рассылку заново.",
reply_markup=build_admin_back_kb("sender"),
)
await state.clear()
return
tg_ids, total_users = await get_recipients(session, send_to, cluster_name)
if keyboard:
try:
keyboard.model_dump()
except Exception as e:
logger.error(f"Ошибка валидации клавиатуры перед рассылкой: {e}")
await callback_query.message.edit_text(
f"❌ <b>Ошибка валидации клавиатуры!</b>\n\n"
f"Клавиатура не прошла финальную проверку перед рассылкой.\n"
f"Ошибка: {str(e)}\n\n"
f"Пожалуйста, создайте рассылку заново.",
reply_markup=build_admin_back_kb("sender"),
)
await state.clear()
return
await callback_query.message.edit_text(f"📤 <b>Рассылка начата!</b>\n👥 Количество получателей: {total_users}")
messages = []
+1 -5
View File
@@ -486,11 +486,7 @@ async def finalize_key_creation(
)
if not remnawave_link:
if bool(MODES_CONFIG.get("HAPP_CRYPTOLINK_ENABLED", HAPP_CRYPTOLINK)):
happ = sub.get("happ") or {}
remnawave_link = happ.get("cryptoLink") or happ.get("link")
if not remnawave_link:
remnawave_link = sub.get("subscriptionUrl")
remnawave_link = sub.get("subscriptionUrl")
if old_key_name:
await session.execute(
@@ -172,6 +172,9 @@ async def make_aggregated_link(
):
logger.info("[agg_link] choose override Remnawave (non-vless)")
return remna_link_override
if sub_url and sub_url.startswith("happ://"):
logger.info("[agg_link] choose Remnawave cryptoLink (non-vless)")
return sub_url
kd = await get_key_details(session, email)
stored = kd.get("remnawave_link") if kd else None
if stored:
+7 -29
View File
@@ -115,6 +115,7 @@ async def create_key_on_cluster(
remnawave_created = False
remnawave_key = None
remnawave_client_id = None
remnawave_link_value = None
if remnawave_servers:
remna = RemnawaveAPI(remnawave_servers[0]["api_url"])
@@ -146,38 +147,15 @@ async def create_key_on_cluster(
if result:
remnawave_created = True
remnawave_client_id = result.get("uuid")
link_vless = None
remnawave_link_value = result.get("subscriptionUrl")
remnawave_key = None
if need_vless_key:
try:
link_vless = await get_vless_link_for_remnawave_by_username(remna, email, email)
remnawave_key = await get_vless_link_for_remnawave_by_username(remna, email, email)
except Exception as e:
logger.error(f"{PANEL_REMNA} Ошибка сборки VLESS: {e}")
base_use_crypto_link = bool(
MODES_CONFIG.get("HAPP_CRYPTOLINK_ENABLED", HAPP_CRYPTOLINK)
)
use_crypto_link = base_use_crypto_link
try:
hook_results = await run_hooks(
"happ_cryptolink_override",
cluster_id=cluster_id,
plan=plan,
session=session,
email=email,
tg_id=tg_id,
happ_cryptolink=base_use_crypto_link,
)
if hook_results:
for hook_result in hook_results:
if hook_result is True or hook_result is False:
use_crypto_link = hook_result
break
except Exception as e:
logger.warning(f"[HAPP_CRYPTOLINK_OVERRIDE] Ошибка при применении хуков: {e}")
remnawave_key = link_vless or (
result["happ"]["cryptoLink"] if use_crypto_link else result.get("subscriptionUrl")
)
logger.info(f"{PANEL_REMNA} Пользователь создан: {result}")
else:
logger.warning(f"{PANEL_REMNA} Нет inbound_id у серверов")
@@ -246,7 +224,7 @@ async def create_key_on_cluster(
expiry_time=expiry_timestamp,
key=public_link,
server_id=server_id_to_store,
remnawave_link=remnawave_key,
remnawave_link=remnawave_link_value if remnawave_created else None,
tariff_id=plan,
)
await session.execute(update(User).where(User.tg_id == tg_id, User.trial.in_([0, -1])).values(trial=1))
+18
View File
@@ -287,6 +287,24 @@ async def renew_key_in_cluster(
await update_key_expiry(session, client_id, new_expiry_time)
for prefix in ["key_24h", "key_10h", "key_expired", "renew"]:
await delete_notification(session, tg_id, f"{email}_{prefix}")
try:
key_link = await make_aggregated_link(
session=session,
cluster_all=cluster_scope,
cluster_id=cluster_id,
email=email,
client_id=client_id,
tg_id=tg_id,
subgroup_code=target_subgroup,
remna_link_override=None,
plan=plan,
)
if key_link:
await update_key_link(session, email, key_link)
except Exception as le:
logger.warning(f"[Link] ошибка генерации/сохранения после продления: {le}")
return True
return False
+9 -6
View File
@@ -6,7 +6,7 @@ from sqlalchemy import delete, select
from sqlalchemy.ext.asyncio import AsyncSession
from config import PUBLIC_LINK, REMNAWAVE_LOGIN, REMNAWAVE_PASSWORD, SUPERNODE
from database import filter_cluster_by_subgroup, get_servers, store_key
from database import filter_cluster_by_subgroup, get_servers, get_tariff_by_id, store_key
from database.models import Key, Tariff
from handlers.utils import get_least_loaded_cluster
from logger import (
@@ -62,6 +62,7 @@ async def update_key_on_cluster(
remnawave_client_id = None
remnawave_key = None
remnawave_link_value = None
if remnawave_servers:
inbound_ids = [s["inbound_id"] for s in remnawave_servers if s.get("inbound_id")]
@@ -104,7 +105,9 @@ async def update_key_on_cluster(
result = await remna.create_user(user_data)
if result:
remnawave_client_id = result.get("uuid")
remnawave_key = result.get("subscriptionUrl")
remnawave_link_value = result.get("subscriptionUrl")
remnawave_key = None
logger.info(f"{PANEL_REMNA} Клиент заново создан, uuid={remnawave_client_id}")
else:
logger.error(f"{PANEL_REMNA} Ошибка создания клиента")
@@ -162,7 +165,7 @@ async def update_key_on_cluster(
await asyncio.gather(*tasks, return_exceptions=True)
logger.info(f"[Update] Ключ {remnawave_client_id} обновлён на серверах подгруппы в {cluster_id}")
return remnawave_client_id, remnawave_key
return remnawave_client_id, remnawave_link_value
except Exception as e:
logger.error(f"[Update Error] Ошибка при обновлении ключа {client_id} на {cluster_id}: {e}")
@@ -246,7 +249,7 @@ async def update_subscription(
traffic_limit = int(tariff.traffic_limit) if tariff.traffic_limit is not None else None
device_limit = int(tariff.device_limit) if tariff.device_limit is not None else 0
new_client_id, remnawave_key = await update_key_on_cluster(
new_client_id, remnawave_link_value = await update_key_on_cluster(
tg_id=tg_id,
client_id=client_id,
email=email,
@@ -267,7 +270,7 @@ async def update_subscription(
client_id=new_client_id,
tg_id=tg_id,
subgroup_code=subgroup_code,
remna_link_override=remnawave_key,
remna_link_override=None,
plan=tariff_id,
)
@@ -280,7 +283,7 @@ async def update_subscription(
email=email,
expiry_time=expiry_time,
key=final_key_link,
remnawave_link=remnawave_key,
remnawave_link=remnawave_link_value or remnawave_link,
server_id=new_cluster_id,
tariff_id=tariff_id,
alias=alias,