freezing subscriptions for admins/ organizing selection in country mode

This commit is contained in:
Vladless
2025-11-16 05:08:48 +03:00
parent b109834543
commit 0385e15815
3 changed files with 175 additions and 12 deletions
+19 -1
View File
@@ -9,7 +9,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
from config import HWID_RESET_BUTTON
from database import get_clusters
from database.models import Key, Tariff
from handlers.buttons import BACK
from handlers.buttons import BACK, FREEZE, UNFREEZE
from handlers.utils import format_days
from hooks.hook_buttons import insert_hook_buttons
from hooks.hooks import run_hooks
@@ -246,6 +246,8 @@ def build_user_key_kb(tg_id: int, email: str) -> InlineKeyboardMarkup:
def build_key_edit_kb(key_details: dict, email: str) -> InlineKeyboardMarkup:
builder = InlineKeyboardBuilder()
is_frozen = key_details.get("is_frozen") if isinstance(key_details, dict) else getattr(key_details, "is_frozen", False)
builder.button(
text="⏳ Время истечения",
callback_data=AdminUserEditorCallback(
@@ -274,6 +276,22 @@ def build_key_edit_kb(key_details: dict, email: str) -> InlineKeyboardMarkup:
action="users_reset_traffic", data=email, tg_id=key_details["tg_id"]
).pack(),
)
if is_frozen:
builder.button(
text=UNFREEZE,
callback_data=AdminUserEditorCallback(
action="users_unfreeze", data=email, tg_id=key_details["tg_id"]
).pack(),
)
else:
builder.button(
text=FREEZE,
callback_data=AdminUserEditorCallback(
action="users_freeze", data=email, tg_id=key_details["tg_id"]
).pack(),
)
if HWID_RESET_BUTTON:
builder.button(
text="💻 HWID",
+138 -2
View File
@@ -1,4 +1,5 @@
import asyncio
import time
import uuid
from datetime import datetime, timedelta, timezone
@@ -21,6 +22,8 @@ from database import (
get_servers,
get_tariff_by_id,
get_tariffs_for_cluster,
mark_key_as_frozen,
mark_key_as_unfrozen,
update_key_expiry,
)
from database.models import Key, Server, Tariff
@@ -31,9 +34,10 @@ from handlers.keys.operations import (
get_user_traffic,
renew_key_in_cluster,
reset_traffic_in_cluster,
toggle_client_on_cluster,
update_subscription,
)
from handlers.utils import generate_random_email
from handlers.utils import generate_random_email, handle_error
from logger import logger
from ..panel.keyboard import AdminPanelCallback, build_admin_back_btn, build_admin_back_kb
@@ -72,7 +76,7 @@ async def handle_key_edit(
if not key_obj:
await callback_query.message.edit_text(
text="🚫 Информация о ключе не найдена.",
text="🚫 Информация о подписке не найдена.",
reply_markup=build_editor_kb(callback_data.tg_id),
)
return
@@ -983,6 +987,138 @@ async def handle_reset_traffic(
)
@router.callback_query(
AdminUserEditorCallback.filter(F.action == "users_freeze"),
IsAdminFilter(),
)
async def handle_admin_freeze_subscription(
callback_query: CallbackQuery,
callback_data: AdminUserEditorCallback,
session: AsyncSession,
):
tg_id = callback_data.tg_id
email = str(callback_data.data)
try:
record = await get_key_details(session, email)
if not record:
await callback_query.message.edit_text(
text="🚫 Информация о ключе не найдена.",
reply_markup=build_editor_kb(tg_id),
)
return
client_id = record["client_id"]
cluster_id = record["server_id"]
result = await toggle_client_on_cluster(cluster_id, email, client_id, enable=False, session=session)
if result["status"] != "success":
text_error = (
"Произошла ошибка при заморозке подписки.\n"
f"Детали: {result.get('error') or result.get('results')}"
)
await callback_query.message.edit_text(
text_error,
reply_markup=build_editor_kb(tg_id, True),
)
return
now_ms = int(time.time() * 1000)
time_left = record["expiry_time"] - now_ms
if time_left < 0:
time_left = 0
await mark_key_as_frozen(session, record["tg_id"], client_id, time_left)
await session.commit()
await callback_query.answer("✅ Подписка заморожена")
await handle_key_edit(
callback_query=callback_query,
callback_data=callback_data,
session=session,
update=False,
)
except Exception as e:
await handle_error(tg_id, callback_query, f"Ошибка при заморозке подписки: {e}")
@router.callback_query(
AdminUserEditorCallback.filter(F.action == "users_unfreeze"),
IsAdminFilter(),
)
async def handle_admin_unfreeze_subscription(
callback_query: CallbackQuery,
callback_data: AdminUserEditorCallback,
session: AsyncSession,
):
tg_id = callback_data.tg_id
email = str(callback_data.data)
try:
record = await get_key_details(session, email)
if not record:
await callback_query.message.edit_text(
text="🚫 Информация о ключе не найдена.",
reply_markup=build_editor_kb(tg_id),
)
return
client_id = record["client_id"]
cluster_id = record["server_id"]
result = await toggle_client_on_cluster(cluster_id, email, client_id, enable=True, session=session)
if result["status"] != "success":
text_error = (
"Произошла ошибка при включении подписки.\n"
f"Детали: {result.get('error') or result.get('results')}"
)
await callback_query.message.edit_text(
text_error,
reply_markup=build_editor_kb(tg_id, True),
)
return
tariff = await get_tariff_by_id(session, record["tariff_id"]) if record.get("tariff_id") else None
if not tariff:
total_gb = 0
hwid_limit = 0
else:
total_gb = int(tariff.get("traffic_limit") or 0)
hwid_limit = int(tariff.get("device_limit") or 0)
now_ms = int(time.time() * 1000)
leftover = record["expiry_time"]
if leftover < 0:
leftover = 0
new_expiry_time = now_ms + leftover
await mark_key_as_unfrozen(session, record["tg_id"], client_id, new_expiry_time)
await session.commit()
await renew_key_in_cluster(
cluster_id=cluster_id,
email=email,
client_id=client_id,
new_expiry_time=new_expiry_time,
total_gb=total_gb,
session=session,
hwid_device_limit=hwid_limit,
reset_traffic=False,
)
await callback_query.answer("✅ Подписка разморожена")
await handle_key_edit(
callback_query=callback_query,
callback_data=callback_data,
session=session,
update=False,
)
except Exception as e:
await handle_error(tg_id, callback_query, f"Ошибка при включении подписки: {e}")
async def change_expiry_time(expiry_time: int, email: str, session: AsyncSession) -> Exception | None:
result = await session.execute(select(Key.client_id, Key.tariff_id, Key.server_id).where(Key.email == email))
row = result.first()
+18 -9
View File
@@ -160,12 +160,16 @@ async def key_country_mode(
builder = InlineKeyboardBuilder()
ts = int(expiry_time.timestamp())
for server_name in available_servers:
if old_key_name:
callback_data = f"select_country|{server_name}|{ts}|{old_key_name}"
else:
callback_data = f"select_country|{server_name}|{ts}"
builder.row(InlineKeyboardButton(text=server_name, callback_data=callback_data))
for i in range(0, len(available_servers), 2):
row_buttons = []
for server_name in available_servers[i : i + 2]:
if old_key_name:
callback_data = f"select_country|{server_name}|{ts}|{old_key_name}"
else:
callback_data = f"select_country|{server_name}|{ts}"
row_buttons.append(InlineKeyboardButton(text=server_name, callback_data=callback_data))
builder.row(*row_buttons)
builder.row(InlineKeyboardButton(text=MAIN_MENU, callback_data="profile"))
@@ -263,9 +267,14 @@ async def change_location_callback(callback_query: CallbackQuery, session: Any):
return
builder = InlineKeyboardBuilder()
for country in available_servers:
callback_data = f"select_country|{country}|{ts}|{old_key_name}"
builder.row(InlineKeyboardButton(text=country, callback_data=callback_data))
for i in range(0, len(available_servers), 2):
row_buttons = []
for country in available_servers[i : i + 2]:
callback_data = f"select_country|{country}|{ts}|{old_key_name}"
row_buttons.append(InlineKeyboardButton(text=country, callback_data=callback_data))
builder.row(*row_buttons)
builder.row(InlineKeyboardButton(text=BACK, callback_data=f"view_key|{old_key_name}"))
await edit_or_send_message(