Add bulk cluster extend / HWID reset on device limit downgrade
This commit is contained in:
@@ -147,46 +147,99 @@ async def handle_days_input(message: Message, state: FSMContext, session: AsyncS
|
||||
await state.clear()
|
||||
return
|
||||
|
||||
for key in keys:
|
||||
new_expiry = key.expiry_time + add_ms
|
||||
servers = await get_servers(session=session)
|
||||
cluster_servers = servers.get(cluster_name, [])
|
||||
|
||||
traffic_limit = 0
|
||||
device_limit = 0
|
||||
key_subgroup = None
|
||||
if key.tariff_id:
|
||||
result = await session.execute(
|
||||
select(Tariff.traffic_limit, Tariff.device_limit, Tariff.subgroup_title).where(
|
||||
Tariff.id == key.tariff_id,
|
||||
Tariff.is_active.is_(True),
|
||||
)
|
||||
)
|
||||
tariff = result.first()
|
||||
if tariff:
|
||||
traffic_limit = int(tariff[0]) if tariff[0] is not None else 0
|
||||
device_limit = int(tariff[1]) if tariff[1] is not None else 0
|
||||
key_subgroup = tariff[2]
|
||||
if not cluster_servers:
|
||||
await message.answer("❌ Не найдены серверы в кластере.")
|
||||
await state.clear()
|
||||
return
|
||||
|
||||
await renew_key_in_cluster(
|
||||
cluster_name,
|
||||
email=key.email,
|
||||
client_id=key.client_id,
|
||||
new_expiry_time=new_expiry,
|
||||
total_gb=traffic_limit,
|
||||
session=session,
|
||||
hwid_device_limit=device_limit,
|
||||
reset_traffic=False,
|
||||
target_subgroup=key_subgroup,
|
||||
old_subgroup=key_subgroup,
|
||||
plan=key.tariff_id,
|
||||
)
|
||||
await update_key_expiry(session, key.client_id, new_expiry)
|
||||
|
||||
logger.info(f"[Cluster Extend] {key.email} +{days}д → {datetime.utcfromtimestamp(new_expiry / 1000)}")
|
||||
|
||||
await message.answer(
|
||||
f"✅ Время подписки продлено на <b>{days} дней</b> всем пользователям в кластере <b>{cluster_name}</b>."
|
||||
is_full_remnawave = all(
|
||||
str(s.get("panel_type", "")).lower() == "remnawave"
|
||||
for s in cluster_servers
|
||||
)
|
||||
|
||||
if is_full_remnawave:
|
||||
uuids = [key.client_id for key in keys if key.client_id]
|
||||
|
||||
if not uuids:
|
||||
await message.answer("❌ Нет валидных подписок для продления.")
|
||||
await state.clear()
|
||||
return
|
||||
|
||||
api_url = cluster_servers[0].get("api_url", "")
|
||||
if not api_url:
|
||||
await message.answer("❌ Не найден URL панели для кластера.")
|
||||
await state.clear()
|
||||
return
|
||||
|
||||
from panels.remnawave import RemnawaveAPI
|
||||
remna = RemnawaveAPI(api_url)
|
||||
|
||||
try:
|
||||
result_bulk = await remna.bulk_extend_expiration_date(uuids, days)
|
||||
finally:
|
||||
await remna.aclose()
|
||||
|
||||
if result_bulk is None:
|
||||
await message.answer("❌ Ошибка при обращении к API панели.")
|
||||
await state.clear()
|
||||
return
|
||||
|
||||
affected = result_bulk.get("affectedRows", 0)
|
||||
logger.info(f"[Cluster Extend] Bulk API: продлено {affected} подписок на {days} дней")
|
||||
|
||||
for key in keys:
|
||||
new_expiry = key.expiry_time + add_ms
|
||||
await update_key_expiry(session, key.client_id, new_expiry)
|
||||
|
||||
await session.commit()
|
||||
|
||||
await message.answer(
|
||||
f"✅ Время подписки продлено на <b>{days} дней</b> для <b>{affected}</b> пользователей в кластере <b>{cluster_name}</b>."
|
||||
)
|
||||
else:
|
||||
for key in keys:
|
||||
new_expiry = key.expiry_time + add_ms
|
||||
|
||||
traffic_limit = 0
|
||||
device_limit = 0
|
||||
key_subgroup = None
|
||||
if key.tariff_id:
|
||||
tariff_result = await session.execute(
|
||||
select(Tariff.traffic_limit, Tariff.device_limit, Tariff.subgroup_title).where(
|
||||
Tariff.id == key.tariff_id,
|
||||
Tariff.is_active.is_(True),
|
||||
)
|
||||
)
|
||||
tariff = tariff_result.first()
|
||||
if tariff:
|
||||
traffic_limit = int(tariff[0]) if tariff[0] is not None else 0
|
||||
device_limit = int(tariff[1]) if tariff[1] is not None else 0
|
||||
key_subgroup = tariff[2]
|
||||
|
||||
await renew_key_in_cluster(
|
||||
cluster_name,
|
||||
email=key.email,
|
||||
client_id=key.client_id,
|
||||
new_expiry_time=new_expiry,
|
||||
total_gb=traffic_limit,
|
||||
session=session,
|
||||
hwid_device_limit=device_limit,
|
||||
reset_traffic=False,
|
||||
target_subgroup=key_subgroup,
|
||||
old_subgroup=key_subgroup,
|
||||
plan=key.tariff_id,
|
||||
)
|
||||
await update_key_expiry(session, key.client_id, new_expiry)
|
||||
|
||||
logger.info(f"[Cluster Extend] {key.email} +{days}д → {datetime.utcfromtimestamp(new_expiry / 1000)}")
|
||||
|
||||
await message.answer(
|
||||
f"✅ Время подписки продлено на <b>{days} дней</b> всем пользователям в кластере <b>{cluster_name}</b>."
|
||||
)
|
||||
|
||||
except ValueError:
|
||||
await message.answer("❌ Введите корректное число дней.")
|
||||
except Exception as e:
|
||||
|
||||
@@ -58,6 +58,7 @@ async def renew_on_remnawave(
|
||||
reset_traffic: bool,
|
||||
target_server_name: str | None = None,
|
||||
external_squad_uuid: str | None = None,
|
||||
old_device_limit: int | None = None,
|
||||
) -> bool:
|
||||
remnawave_nodes = [
|
||||
s for s in cluster if str(s.get("panel_type", "3x-ui")).lower() == "remnawave" and s.get("inbound_id")
|
||||
@@ -74,6 +75,13 @@ async def renew_on_remnawave(
|
||||
logger.error(f"{PANEL_REMNA} Не удалось войти в Remnawave API")
|
||||
return False
|
||||
|
||||
if old_device_limit is not None and hwid_device_limit < old_device_limit:
|
||||
try:
|
||||
await remna.clear_all_hwid_devices(client_id)
|
||||
logger.info(f"{PANEL_REMNA} HWID устройства сброшены для {client_id} (лимит {old_device_limit} → {hwid_device_limit})")
|
||||
except Exception as e:
|
||||
logger.warning(f"{PANEL_REMNA} Ошибка сброса HWID: {e}")
|
||||
|
||||
expire_iso = datetime.utcfromtimestamp(new_expiry_time // 1000).isoformat() + "Z"
|
||||
traffic_limit_bytes = total_gb * 1024 * 1024 * 1024 if total_gb else 0
|
||||
active_inbounds = [s["inbound_id"] for s in remnawave_nodes]
|
||||
@@ -203,6 +211,12 @@ async def renew_key_in_cluster(
|
||||
tg_id = int(kd["tg_id"])
|
||||
server_id = kd["server_id"]
|
||||
|
||||
old_device_limit = kd.get("current_device_limit") or kd.get("selected_device_limit")
|
||||
if old_device_limit is None and kd.get("tariff_id"):
|
||||
old_tariff = await get_tariff_by_id(session, kd["tariff_id"])
|
||||
if old_tariff:
|
||||
old_device_limit = old_tariff.get("device_limit")
|
||||
|
||||
single_server = None
|
||||
if servers_map.get(server_id):
|
||||
cluster = servers_map[server_id]
|
||||
@@ -330,6 +344,7 @@ async def renew_key_in_cluster(
|
||||
reset_traffic=reset_traffic,
|
||||
target_server_name=server_id if single_server else None,
|
||||
external_squad_uuid=external_squad_uuid,
|
||||
old_device_limit=old_device_limit,
|
||||
)
|
||||
|
||||
succeeded, _ = await renew_on_3xui(
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user