diff --git a/handlers/admin/clusters/clusters_handler.py b/handlers/admin/clusters/clusters_handler.py
index f9dbad14..20f0cecf 100644
--- a/handlers/admin/clusters/clusters_handler.py
+++ b/handlers/admin/clusters/clusters_handler.py
@@ -1,5 +1,5 @@
import asyncio
-from datetime import datetime
+from datetime import datetime, timezone
from typing import Any
from aiogram import F, Router, types
@@ -582,38 +582,83 @@ async def handle_sync_cluster(
)
return
+ servers = await get_servers(session)
+ cluster_servers = servers.get(cluster_name, [])
+ only_remnawave = all(s.get("panel_type") == "remnawave" for s in cluster_servers)
+
await callback_query.message.edit_text(
text=f"π Π‘ΠΈΠ½Ρ
ΡΠΎΠ½ΠΈΠ·Π°ΡΠΈΡ ΠΊΠ»Π°ΡΡΠ΅ΡΠ° {cluster_name}\n\nπ ΠΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ ΠΊΠ»ΡΡΠ΅ΠΉ: {len(keys_to_sync)}"
)
for key in keys_to_sync:
try:
- await delete_key_from_cluster(
- cluster_name, key["email"], key["client_id"], session
- )
-
- await session.execute(
- delete(Key).where(
- Key.tg_id == key["tg_id"], Key.client_id == key["client_id"]
+ if only_remnawave:
+ expire_iso = (
+ datetime.utcfromtimestamp(key["expiry_time"] / 1000)
+ .replace(tzinfo=timezone.utc)
+ .isoformat()
)
- )
- await create_key_on_cluster(
- cluster_name,
- key["tg_id"],
- key["client_id"],
- key["email"],
- key["expiry_time"],
- plan=key["tariff_id"],
- session=session,
- remnawave_link=key["remnawave_link"],
- )
+ remna = RemnawaveAPI(cluster_servers[0]["api_url"])
+ if not await remna.login(REMNAWAVE_LOGIN, REMNAWAVE_PASSWORD):
+ raise Exception("ΠΠ΅ ΡΠ΄Π°Π»ΠΎΡΡ Π°Π²ΡΠΎΡΠΈΠ·ΠΎΠ²Π°ΡΡΡΡ Π² Remnawave")
+
+ traffic_limit_bytes = 0
+ hwid_limit = None
+ if key["tariff_id"]:
+ tariff = await session.get(Tariff, key["tariff_id"])
+ if tariff:
+ traffic_limit_bytes = int(tariff.traffic_limit * 1024**3)
+ hwid_limit = tariff.device_limit
+ else:
+ logger.warning(f"[Sync] ΠΠ»ΡΡ {key['client_id']} Ρ Π½Π΅ΡΡΡΠ΅ΡΡΠ²ΡΡΡΠΈΠΌ ΡΠ°ΡΠΈΡΠΎΠΌ ID={key['tariff_id']} β ΠΎΠ±Π½ΠΎΠ²ΠΈΠΌ Π±Π΅Π· Π»ΠΈΠΌΠΈΡΠΎΠ²")
+
+ valid_email = f"{key['email']}@fake.local"
+
+ inbound_ids = [
+ s["inbound_id"]
+ for s in cluster_servers
+ if s.get("inbound_id")
+ ]
+
+ await remna.update_user(
+ uuid=key["client_id"],
+ expire_at=expire_iso,
+ telegram_id=key["tg_id"],
+ email=valid_email,
+ active_user_inbounds=inbound_ids,
+ traffic_limit_bytes=traffic_limit_bytes,
+ hwid_device_limit=hwid_limit,
+ )
+
+ else:
+ await delete_key_from_cluster(
+ cluster_name, key["email"], key["client_id"], session
+ )
+
+ await session.execute(
+ delete(Key).where(
+ Key.tg_id == key["tg_id"],
+ Key.client_id == key["client_id"]
+ )
+ )
+
+ await create_key_on_cluster(
+ cluster_name,
+ key["tg_id"],
+ key["client_id"],
+ key["email"],
+ key["expiry_time"],
+ plan=key["tariff_id"],
+ session=session,
+ remnawave_link=key["remnawave_link"],
+ )
await asyncio.sleep(0.5)
except Exception as e:
logger.error(
- f"ΠΡΠΈΠ±ΠΊΠ° ΠΏΡΠΈ ΡΠΈΠ½Ρ
ΡΠΎΠ½ΠΈΠ·Π°ΡΠΈΠΈ ΠΊΠ»ΡΡΠ° {key['client_id']} Π² {cluster_name}: {e}"
+ f"[Sync] ΠΡΠΈΠ±ΠΊΠ° ΠΏΡΠΈ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠ΅ ΠΊΠ»ΡΡΠ° {key['client_id']} Π² {cluster_name}: {e}"
)
await callback_query.message.edit_text(
@@ -622,7 +667,7 @@ async def handle_sync_cluster(
)
except Exception as e:
- logger.error(f"ΠΡΠΈΠ±ΠΊΠ° ΡΠΈΠ½Ρ
ΡΠΎΠ½ΠΈΠ·Π°ΡΠΈΠΈ ΠΊΠ»ΡΡΠ΅ΠΉ Π² ΠΊΠ»Π°ΡΡΠ΅ΡΠ΅ {cluster_name}: {e}")
+ logger.error(f"[Sync] ΠΡΠΈΠ±ΠΊΠ° ΡΠΈΠ½Ρ
ΡΠΎΠ½ΠΈΠ·Π°ΡΠΈΠΈ ΠΊΠ»Π°ΡΡΠ΅ΡΠ° {cluster_name}: {e}")
await callback_query.message.edit_text(
text=f"β ΠΡΠΎΠΈΠ·ΠΎΡΠ»Π° ΠΎΡΠΈΠ±ΠΊΠ° ΠΏΡΠΈ ΡΠΈΠ½Ρ
ΡΠΎΠ½ΠΈΠ·Π°ΡΠΈΠΈ: {e}",
reply_markup=build_admin_back_kb("clusters"),
diff --git a/handlers/keys/key_renew.py b/handlers/keys/key_renew.py
index 75b2f000..8c54cdbf 100644
--- a/handlers/keys/key_renew.py
+++ b/handlers/keys/key_renew.py
@@ -110,7 +110,7 @@ async def process_callback_renew_key(
builder = InlineKeyboardBuilder()
for t in selected_tariffs:
- button_text = f"π
{t['name']} β {t['price_rub']}β½"
+ button_text = f"{t['name']} β {t['price_rub']}β½"
builder.row(
InlineKeyboardButton(
text=button_text,