411 lines
14 KiB
Python
411 lines
14 KiB
Python
from aiogram.filters.callback_data import CallbackData
|
||
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
|
||
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||
|
||
from ..panel.keyboard import AdminPanelCallback, build_admin_back_btn
|
||
from ..servers.keyboard import AdminServerCallback
|
||
from handlers.buttons import BACK
|
||
|
||
|
||
class AdminClusterCallback(CallbackData, prefix="admin_cluster"):
|
||
action: str
|
||
data: str | None = None
|
||
|
||
|
||
def build_clusters_editor_kb(servers: dict) -> InlineKeyboardMarkup:
|
||
builder = InlineKeyboardBuilder()
|
||
|
||
cluster_names = list(servers.keys())
|
||
for i in range(0, len(cluster_names), 2):
|
||
row_buttons = []
|
||
for name in cluster_names[i : i + 2]:
|
||
servers_in_cluster = servers[name]
|
||
all_disabled = all(not s["enabled"] for s in servers_in_cluster)
|
||
label = f"❌ {name} (отключен)" if all_disabled else f"⚙️ {name}"
|
||
row_buttons.append(
|
||
InlineKeyboardButton(
|
||
text=label,
|
||
callback_data=AdminClusterCallback(action="manage", data=name).pack(),
|
||
)
|
||
)
|
||
builder.row(*row_buttons)
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text="➕ Добавить кластер",
|
||
callback_data=AdminClusterCallback(action="add").pack(),
|
||
)
|
||
)
|
||
|
||
builder.row(build_admin_back_btn())
|
||
|
||
return builder.as_markup()
|
||
|
||
|
||
def build_manage_cluster_kb(cluster_servers: list, cluster_name: str) -> InlineKeyboardMarkup:
|
||
builder = InlineKeyboardBuilder()
|
||
|
||
for server in cluster_servers:
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text=f"🌍 {server['server_name']}",
|
||
callback_data=AdminServerCallback(action="manage", data=server["server_name"]).pack(),
|
||
)
|
||
)
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text="➕ Добавить сервер",
|
||
callback_data=AdminServerCallback(action="add", data=cluster_name).pack(),
|
||
)
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text="💸 Тариф(Установить/изменить)",
|
||
callback_data=AdminClusterCallback(action="attach_tariff_menu", data=cluster_name).pack(),
|
||
)
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text=BACK,
|
||
callback_data=AdminClusterCallback(action="manage", data=cluster_name).pack(),
|
||
)
|
||
)
|
||
|
||
return builder.as_markup()
|
||
|
||
|
||
def build_attach_tariff_kb(cluster_name: str) -> InlineKeyboardMarkup:
|
||
builder = InlineKeyboardBuilder()
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text="📋 Привязать тарифы",
|
||
callback_data=AdminClusterCallback(action="set_subgroup", data=cluster_name).pack(),
|
||
),
|
||
InlineKeyboardButton(
|
||
text="🧹 Сбросить",
|
||
callback_data=AdminClusterCallback(action="reset_cluster_subgroups", data=cluster_name).pack(),
|
||
),
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text="🗂 Спецгруппы",
|
||
callback_data=AdminClusterCallback(action="set_group", data=cluster_name).pack(),
|
||
),
|
||
InlineKeyboardButton(
|
||
text="🧹 Сбросить",
|
||
callback_data=AdminClusterCallback(action="reset_cluster_groups", data=cluster_name).pack(),
|
||
),
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text=BACK,
|
||
callback_data=AdminClusterCallback(action="manage", data=cluster_name).pack(),
|
||
)
|
||
)
|
||
return builder.as_markup()
|
||
|
||
|
||
def build_legacy_reset_kb(cluster_name: str) -> InlineKeyboardMarkup:
|
||
builder = InlineKeyboardBuilder()
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text="🧹 Сбросить привязки",
|
||
callback_data=AdminClusterCallback(action="reset_cluster_subgroups", data=cluster_name).pack(),
|
||
)
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text=BACK,
|
||
callback_data=AdminClusterCallback(action="attach_tariff_menu", data=cluster_name).pack(),
|
||
)
|
||
)
|
||
return builder.as_markup()
|
||
|
||
|
||
def build_select_subgroup_servers_kb(
|
||
cluster_name: str, cluster_servers: list, selected: set[str]
|
||
) -> InlineKeyboardMarkup:
|
||
builder = InlineKeyboardBuilder()
|
||
names = []
|
||
for s in cluster_servers:
|
||
if isinstance(s, str):
|
||
names.append(s)
|
||
elif isinstance(s, dict):
|
||
names.append(s.get("server_name") or s.get("name") or str(s))
|
||
else:
|
||
names.append(getattr(s, "server_name", None) or getattr(s, "name", None) or str(s))
|
||
|
||
for i, name in enumerate(names):
|
||
mark = "✅" if name in selected else "⬜️"
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text=f"{mark} {name}",
|
||
callback_data=AdminClusterCallback(action="toggle_server_subgroup", data=f"{cluster_name}|{i}").pack(),
|
||
)
|
||
)
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text="📋 Выбрать тарифы",
|
||
callback_data=AdminClusterCallback(action="choose_subgroup", data=cluster_name).pack(),
|
||
)
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text="♻️ Сбросить выбор",
|
||
callback_data=AdminClusterCallback(action="reset_subgroup_selection", data=cluster_name).pack(),
|
||
)
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text=BACK,
|
||
callback_data=AdminClusterCallback(action="attach_tariff_menu", data=cluster_name).pack(),
|
||
)
|
||
)
|
||
|
||
return builder.as_markup()
|
||
|
||
|
||
def build_tariff_subgroup_selection_kb(cluster_name: str, subgroups: list[str]) -> InlineKeyboardMarkup:
|
||
builder = InlineKeyboardBuilder()
|
||
for i, title in enumerate(subgroups):
|
||
builder.button(
|
||
text=title,
|
||
callback_data=AdminClusterCallback(action="apply_tariff_subgroup", data=f"{cluster_name}|{i}").pack(),
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text="⬅️ Назад к выбору серверов",
|
||
callback_data=AdminClusterCallback(action="set_subgroup", data=cluster_name).pack(),
|
||
)
|
||
)
|
||
builder.adjust(2, 1)
|
||
return builder.as_markup()
|
||
|
||
|
||
def build_tariff_selection_kb(cluster_name: str, tariffs: list, selected: set[int]) -> InlineKeyboardMarkup:
|
||
builder = InlineKeyboardBuilder()
|
||
|
||
grouped: dict[str | None, list] = {}
|
||
for t in tariffs:
|
||
subgroup = t.subgroup_title
|
||
grouped.setdefault(subgroup, []).append(t)
|
||
|
||
subgroups_sorted = sorted(grouped.keys(), key=lambda x: (x is None, x or ""))
|
||
|
||
for subgroup in subgroups_sorted:
|
||
tariffs_list = grouped[subgroup]
|
||
|
||
if subgroup:
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text=f"━━ {subgroup} ━━",
|
||
callback_data="noop",
|
||
)
|
||
)
|
||
|
||
for t in tariffs_list:
|
||
mark = "✅" if t.id in selected else "⬜️"
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text=f"{mark} {t.name}",
|
||
callback_data=AdminClusterCallback(action="toggle_tariff", data=f"{cluster_name}|{t.id}").pack(),
|
||
)
|
||
)
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text="✅ Применить",
|
||
callback_data=AdminClusterCallback(action="apply_tariffs", data=cluster_name).pack(),
|
||
)
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text="⬅️ Назад к выбору серверов",
|
||
callback_data=AdminClusterCallback(action="set_subgroup", data=cluster_name).pack(),
|
||
)
|
||
)
|
||
|
||
return builder.as_markup()
|
||
|
||
|
||
def build_cluster_management_kb(cluster_name: str) -> InlineKeyboardMarkup:
|
||
builder = InlineKeyboardBuilder()
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text="📡 Серверы",
|
||
callback_data=f"cluster_servers|{cluster_name}",
|
||
)
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text="🌐 Доступность",
|
||
callback_data=AdminClusterCallback(action="availability", data=cluster_name).pack(),
|
||
)
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text="🔄 Синхронизация",
|
||
callback_data=AdminClusterCallback(action="sync", data=cluster_name).pack(),
|
||
)
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text="💾 Создать бэкап",
|
||
callback_data=AdminClusterCallback(action="backup", data=cluster_name).pack(),
|
||
)
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text="⏳ Добавить время",
|
||
callback_data=AdminClusterCallback(action="add_time", data=cluster_name).pack(),
|
||
)
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text="✏️ Сменить название",
|
||
callback_data=AdminClusterCallback(action="rename", data=cluster_name).pack(),
|
||
)
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text="💸 Тариф(Установить/изменить)",
|
||
callback_data=AdminClusterCallback(action="set_tariff", data=cluster_name).pack(),
|
||
)
|
||
)
|
||
builder.row(InlineKeyboardButton(text=BACK, callback_data=AdminPanelCallback(action="clusters").pack()))
|
||
|
||
return builder.as_markup()
|
||
|
||
|
||
def build_sync_cluster_kb(cluster_servers: list, cluster_name: str) -> InlineKeyboardMarkup:
|
||
builder = InlineKeyboardBuilder()
|
||
|
||
for server in cluster_servers:
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text=f"🔄 Синхронизировать {server['server_name']}",
|
||
callback_data=AdminClusterCallback(action="sync-server", data=server["server_name"]).pack(),
|
||
)
|
||
)
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text="📍 Синхронизировать кластер",
|
||
callback_data=AdminClusterCallback(action="sync-cluster", data=cluster_name).pack(),
|
||
)
|
||
)
|
||
|
||
builder.row(build_admin_back_btn("clusters"))
|
||
|
||
return builder.as_markup()
|
||
|
||
|
||
def build_panel_type_kb() -> InlineKeyboardMarkup:
|
||
builder = InlineKeyboardBuilder()
|
||
builder.button(text="🌐 3X-UI", callback_data=AdminClusterCallback(action="panel_3xui").pack())
|
||
builder.button(
|
||
text="🌀 Remnawave",
|
||
callback_data=AdminClusterCallback(action="panel_remnawave").pack(),
|
||
)
|
||
builder.row(build_admin_back_btn("clusters"))
|
||
return builder.as_markup()
|
||
|
||
|
||
def build_tariff_group_selection_kb(cluster_name: str, groups: list[tuple[int, str]]) -> InlineKeyboardMarkup:
|
||
builder = InlineKeyboardBuilder()
|
||
for group_id, group_code in groups:
|
||
builder.button(
|
||
text=group_code,
|
||
callback_data=AdminClusterCallback(action="apply_tariff_group", data=f"{cluster_name}|{group_id}").pack(),
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text=BACK,
|
||
callback_data=AdminClusterCallback(action="manage", data=cluster_name).pack(),
|
||
)
|
||
)
|
||
builder.adjust(2, 1)
|
||
return builder.as_markup()
|
||
|
||
|
||
def build_select_group_servers_kb(cluster_name: str, cluster_servers: list, selected: set[str]) -> InlineKeyboardMarkup:
|
||
builder = InlineKeyboardBuilder()
|
||
names = []
|
||
for s in cluster_servers:
|
||
if isinstance(s, str):
|
||
names.append(s)
|
||
elif isinstance(s, dict):
|
||
names.append(s.get("server_name") or s.get("name") or str(s))
|
||
else:
|
||
names.append(getattr(s, "server_name", None) or getattr(s, "name", None) or str(s))
|
||
|
||
for i, name in enumerate(names):
|
||
mark = "✅" if name in selected else "⬜️"
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text=f"{mark} {name}",
|
||
callback_data=AdminClusterCallback(action="toggle_server_group", data=f"{cluster_name}|{i}").pack(),
|
||
)
|
||
)
|
||
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text="📚 Выбрать спецгруппу",
|
||
callback_data=AdminClusterCallback(action="choose_group", data=cluster_name).pack(),
|
||
)
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text="♻️ Сбросить выбор",
|
||
callback_data=AdminClusterCallback(action="reset_group_selection", data=cluster_name).pack(),
|
||
)
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text=BACK,
|
||
callback_data=AdminClusterCallback(action="manage", data=cluster_name).pack(),
|
||
)
|
||
)
|
||
return builder.as_markup()
|
||
|
||
|
||
def build_tariff_group_selection_for_servers_kb(
|
||
cluster_name: str, groups: list[tuple[int, str]]
|
||
) -> InlineKeyboardMarkup:
|
||
builder = InlineKeyboardBuilder()
|
||
for group_id, group_code in groups:
|
||
builder.button(
|
||
text=group_code,
|
||
callback_data=AdminClusterCallback(
|
||
action="apply_group_to_servers", data=f"{cluster_name}|{group_id}"
|
||
).pack(),
|
||
)
|
||
builder.row(
|
||
InlineKeyboardButton(
|
||
text=BACK,
|
||
callback_data=AdminClusterCallback(action="set_group", data=cluster_name).pack(),
|
||
)
|
||
)
|
||
builder.adjust(2, 1)
|
||
return builder.as_markup()
|
||
|
||
|
||
def build_availability_kb(cluster_name: str) -> InlineKeyboardMarkup:
|
||
return InlineKeyboardMarkup(
|
||
inline_keyboard=[
|
||
[
|
||
InlineKeyboardButton(
|
||
text="🔁 Обновить",
|
||
callback_data=AdminClusterCallback(action="availability", data=cluster_name).pack(),
|
||
)
|
||
],
|
||
[
|
||
InlineKeyboardButton(
|
||
text=BACK, callback_data=AdminClusterCallback(action="manage", data=cluster_name).pack()
|
||
)
|
||
],
|
||
]
|
||
)
|