diff --git a/handlers/admin/clusters/clusters_handler.py b/handlers/admin/clusters/clusters_handler.py
index 1c153731..9bad11ef 100644
--- a/handlers/admin/clusters/clusters_handler.py
+++ b/handlers/admin/clusters/clusters_handler.py
@@ -39,6 +39,8 @@ class AdminClusterStates(StatesGroup):
waiting_for_server_name = State()
waiting_for_subscription_url = State()
waiting_for_days_input = State()
+ waiting_for_new_cluster_name = State()
+ waiting_for_new_server_name = State()
@router.callback_query(
@@ -538,3 +540,195 @@ async def handle_days_input(message: Message, state: FSMContext, session: Any):
await message.answer("❌ Произошла ошибка при продлении времени.")
finally:
await state.clear()
+
+@router.callback_query(AdminClusterCallback.filter(F.action == "rename"), IsAdminFilter())
+async def handle_rename_cluster(callback_query: CallbackQuery, callback_data: AdminClusterCallback, state: FSMContext):
+ cluster_name = callback_data.data
+ await state.update_data(old_cluster_name=cluster_name)
+
+ text = (
+ f"✏️ Введите новое имя для кластера '{cluster_name}':\n\n"
+ "▸ Имя должно быть уникальным.\n"
+ "▸ Имя не должно превышать 12 символов.\n\n"
+ "📌 Пример: new_cluster"
+ )
+
+ await callback_query.message.edit_text(
+ text=text,
+ reply_markup=build_admin_back_kb("clusters"),
+ )
+ await state.set_state(AdminClusterStates.waiting_for_new_cluster_name)
+
+
+@router.message(AdminClusterStates.waiting_for_new_cluster_name, IsAdminFilter())
+async def handle_new_cluster_name_input(message: Message, state: FSMContext, session: Any):
+ if not message.text:
+ await message.answer(
+ text="❌ Имя кластера не может быть пустым! Попробуйте снова.",
+ reply_markup=build_admin_back_kb("clusters"),
+ )
+ return
+
+ new_cluster_name = message.text.strip()
+ if len(new_cluster_name) > 12:
+ await message.answer(
+ text="❌ Имя кластера не должно превышать 12 символов! Попробуйте снова.",
+ reply_markup=build_admin_back_kb("clusters"),
+ )
+ return
+
+ user_data = await state.get_data()
+ old_cluster_name = user_data.get("old_cluster_name")
+
+ conn = await asyncpg.connect(DATABASE_URL)
+ try:
+ existing_cluster = await conn.fetchval(
+ "SELECT cluster_name FROM servers WHERE cluster_name = $1 LIMIT 1",
+ new_cluster_name
+ )
+ if existing_cluster:
+ await message.answer(
+ text=f"❌ Кластер с именем '{new_cluster_name}' уже существует. Введите другое имя.",
+ reply_markup=build_admin_back_kb("clusters"),
+ )
+ return
+
+ keys_count = await conn.fetchval(
+ "SELECT COUNT(*) FROM keys WHERE server_id = $1",
+ old_cluster_name
+ )
+
+ async with conn.transaction():
+ await conn.execute(
+ "UPDATE servers SET cluster_name = $1 WHERE cluster_name = $2",
+ new_cluster_name,
+ old_cluster_name
+ )
+
+ if keys_count > 0:
+ await conn.execute(
+ "UPDATE keys SET server_id = $1 WHERE server_id = $2",
+ new_cluster_name,
+ old_cluster_name
+ )
+
+ await message.answer(
+ text=f"✅ Название кластера успешно изменено с '{old_cluster_name}' на '{new_cluster_name}'!",
+ reply_markup=build_admin_back_kb("clusters"),
+ )
+ except Exception as e:
+ logger.error(f"Ошибка при смене имени кластера {old_cluster_name} на {new_cluster_name}: {e}")
+ await message.answer(
+ text=f"❌ Произошла ошибка при смене имени кластера: {e}",
+ reply_markup=build_admin_back_kb("clusters"),
+ )
+ finally:
+ await conn.close()
+ await state.clear()
+
+
+@router.callback_query(AdminServerCallback.filter(F.action == "rename"), IsAdminFilter())
+async def handle_rename_server(callback_query: CallbackQuery, callback_data: AdminServerCallback, state: FSMContext):
+ old_server_name = callback_data.data
+
+ servers = await get_servers()
+ cluster_name = None
+ for c_name, server_list in servers.items():
+ for server in server_list:
+ if server["server_name"] == old_server_name:
+ cluster_name = c_name
+ break
+ if cluster_name:
+ break
+
+ if not cluster_name:
+ await callback_query.message.edit_text(
+ text=f"❌ Не удалось найти кластер для сервера '{old_server_name}'.",
+ reply_markup=build_admin_back_kb("clusters"),
+ )
+ return
+
+ await state.update_data(old_server_name=old_server_name, cluster_name=cluster_name)
+
+ text = (
+ f"✏️ Введите новое имя для сервера '{old_server_name}' в кластере '{cluster_name}':\n\n"
+ "▸ Имя должно быть уникальным в пределах кластера.\n"
+ "▸ Имя не должно превышать 12 символов.\n\n"
+ "📌 Пример: new_server"
+ )
+
+ await callback_query.message.edit_text(
+ text=text,
+ reply_markup=build_admin_back_kb("clusters"),
+ )
+ await state.set_state(AdminClusterStates.waiting_for_new_server_name)
+
+
+@router.message(AdminClusterStates.waiting_for_new_server_name, IsAdminFilter())
+async def handle_new_server_name_input(message: Message, state: FSMContext, session: Any):
+ if not message.text:
+ await message.answer(
+ text="❌ Имя сервера не может быть пустым! Попробуйте снова.",
+ reply_markup=build_admin_back_kb("clusters"),
+ )
+ return
+
+ new_server_name = message.text.strip()
+ if len(new_server_name) > 12:
+ await message.answer(
+ text="❌ Имя сервера не должно превышать 12 символов! Попробуйте снова.",
+ reply_markup=build_admin_back_kb("clusters"),
+ )
+ return
+
+ user_data = await state.get_data()
+ old_server_name = user_data.get("old_server_name")
+ cluster_name = user_data.get("cluster_name")
+
+ conn = await asyncpg.connect(DATABASE_URL)
+ try:
+ existing_server = await conn.fetchval(
+ "SELECT server_name FROM servers WHERE cluster_name = $1 AND server_name = $2 LIMIT 1",
+ cluster_name,
+ new_server_name
+ )
+ if existing_server:
+ await message.answer(
+ text=f"❌ Сервер с именем '{new_server_name}' уже существует в кластере '{cluster_name}'. Введите другое имя.",
+ reply_markup=build_admin_back_kb("clusters"),
+ )
+ return
+
+ keys_count = await conn.fetchval(
+ "SELECT COUNT(*) FROM keys WHERE server_id = $1",
+ old_server_name
+ )
+
+ async with conn.transaction():
+ await conn.execute(
+ "UPDATE servers SET server_name = $1 WHERE cluster_name = $2 AND server_name = $3",
+ new_server_name,
+ cluster_name,
+ old_server_name
+ )
+
+ if keys_count > 0:
+ await conn.execute(
+ "UPDATE keys SET server_id = $1 WHERE server_id = $2",
+ new_server_name,
+ old_server_name
+ )
+
+ await message.answer(
+ text=f"✅ Название сервера успешно изменено с '{old_server_name}' на '{new_server_name}' в кластере '{cluster_name}'!",
+ reply_markup=build_admin_back_kb("clusters"),
+ )
+ except Exception as e:
+ logger.error(f"Ошибка при смене имени сервера {old_server_name} на {new_server_name}: {e}")
+ await message.answer(
+ text=f"❌ Произошла ошибка при смене имени сервера: {e}",
+ reply_markup=build_admin_back_kb("clusters"),
+ )
+ finally:
+ await conn.close()
+ await state.clear()