feat: CRUD для серверов через Telegram меню
Возможности:
- Добавление сервера через пошаговую форму (имя, host, port, user, tags)
- Редактирование сервера (выбор поля для изменения)
- Удаление сервера (кроме local)
- Сохранение изменений в .env автоматически
UI:
- Меню серверов с кнопками управления (⚙️)
- Пошаговый ввод с валидацией
- Кнопки отмены и пропуска тегов
- Индикация текущего состояния
Серверы:
- add_server(name, host, port, user, tags)
- update_server(name, host, port, user, tags)
- delete_server(name)
- save_to_env() - сохраняет в .env файл
Валидация:
- Имя: только латиница, дефисы, подчёркивания
- Порт: число 1-65535
- Теги: список через запятую
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
parent
4888508795
commit
7a110e6974
455
bot.py
455
bot.py
|
|
@ -211,6 +211,76 @@ class ServerManager:
|
||||||
keyboard.append([button])
|
keyboard.append([button])
|
||||||
return InlineKeyboardMarkup(keyboard)
|
return InlineKeyboardMarkup(keyboard)
|
||||||
|
|
||||||
|
def add_server(self, name: str, host: str, port: int, user: str, tags: List[str] = None) -> bool:
|
||||||
|
"""Добавить сервер."""
|
||||||
|
if name in self._servers:
|
||||||
|
return False
|
||||||
|
self._servers[name] = Server(name=name, host=host, port=port, user=user, tags=tags or [])
|
||||||
|
self.save_to_env()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def update_server(self, name: str, host: str = None, port: int = None,
|
||||||
|
user: str = None, tags: List[str] = None) -> bool:
|
||||||
|
"""Обновить сервер."""
|
||||||
|
if name not in self._servers or name == "local":
|
||||||
|
return False
|
||||||
|
server = self._servers[name]
|
||||||
|
if host:
|
||||||
|
server.host = host
|
||||||
|
if port:
|
||||||
|
server.port = port
|
||||||
|
if user:
|
||||||
|
server.user = user
|
||||||
|
if tags is not None:
|
||||||
|
server.tags = tags
|
||||||
|
self.save_to_env()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def delete_server(self, name: str) -> bool:
|
||||||
|
"""Удалить сервер."""
|
||||||
|
if name not in self._servers or name == "local":
|
||||||
|
return False
|
||||||
|
del self._servers[name]
|
||||||
|
self.save_to_env()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def save_to_env(self):
|
||||||
|
"""Сохранить серверы в .env файл."""
|
||||||
|
env_file = Path(__file__).parent / ".env"
|
||||||
|
|
||||||
|
# Читаем существующий файл
|
||||||
|
lines = []
|
||||||
|
if env_file.exists():
|
||||||
|
with open(env_file, "r", encoding="utf-8") as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
|
||||||
|
# Формируем строку серверов
|
||||||
|
server_parts = []
|
||||||
|
for server in self._servers.values():
|
||||||
|
if server.name == "local":
|
||||||
|
continue
|
||||||
|
tags_str = ",".join(server.tags) if server.tags else ""
|
||||||
|
server_parts.append(f"{server.name}|{server.host}|{server.port}|{server.user}|{tags_str}")
|
||||||
|
|
||||||
|
servers_line = f"SERVERS={','.join(server_parts)}\n"
|
||||||
|
|
||||||
|
# Ищем и обновляем или добавляем строку SERVERS
|
||||||
|
found = False
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if line.startswith("SERVERS="):
|
||||||
|
lines[i] = servers_line
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not found:
|
||||||
|
lines.append("\n" + servers_line)
|
||||||
|
|
||||||
|
# Записываем обратно
|
||||||
|
with open(env_file, "w", encoding="utf-8") as f:
|
||||||
|
f.writelines(lines)
|
||||||
|
|
||||||
|
logger.info(f"Серверы сохранены в {env_file}")
|
||||||
|
|
||||||
|
|
||||||
# --- Хранилище состояний пользователя ---
|
# --- Хранилище состояний пользователя ---
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|
@ -218,11 +288,12 @@ class UserState:
|
||||||
"""Состояние пользователя в диалоге."""
|
"""Состояние пользователя в диалоге."""
|
||||||
current_menu: str = "main"
|
current_menu: str = "main"
|
||||||
waiting_for_input: bool = False
|
waiting_for_input: bool = False
|
||||||
input_type: Optional[str] = None
|
input_type: Optional[str] = None # "name", "host", "port", "user", "tags", "server_action"
|
||||||
parent_menu: Optional[str] = None
|
parent_menu: Optional[str] = None
|
||||||
context: Dict[str, Any] = field(default_factory=dict)
|
context: Dict[str, Any] = field(default_factory=dict)
|
||||||
working_directory: Optional[str] = None
|
working_directory: Optional[str] = None
|
||||||
current_server: str = "local" # Имя текущего сервера
|
current_server: str = "local" # Имя текущего сервера
|
||||||
|
editing_server: Optional[str] = None # Имя сервера, который редактируем
|
||||||
|
|
||||||
|
|
||||||
class StateManager:
|
class StateManager:
|
||||||
|
|
@ -587,36 +658,173 @@ async def menu_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
)
|
)
|
||||||
|
|
||||||
elif callback == "server_menu":
|
elif callback == "server_menu":
|
||||||
# Динамическое обновление меню серверов
|
# Динамическое обновление меню серверов с кнопками управления
|
||||||
servers = server_manager.list_servers()
|
servers = server_manager.list_servers()
|
||||||
keyboard = []
|
keyboard = []
|
||||||
|
|
||||||
for srv in servers:
|
for srv in servers:
|
||||||
keyboard.append([InlineKeyboardButton(
|
# Кнопка выбора сервера + кнопка управления (для не-local)
|
||||||
|
row = [InlineKeyboardButton(
|
||||||
srv.display_name,
|
srv.display_name,
|
||||||
callback_data=f"server_select_{srv.name}"
|
callback_data=f"server_select_{srv.name}"
|
||||||
)])
|
)]
|
||||||
keyboard.append([InlineKeyboardButton("⬅️ Назад", callback_data="main")])
|
if srv.name != "local":
|
||||||
|
row.append(InlineKeyboardButton(
|
||||||
|
"⚙️",
|
||||||
|
callback_data=f"server_manage_{srv.name}"
|
||||||
|
))
|
||||||
|
keyboard.append(row)
|
||||||
|
|
||||||
|
keyboard.append([
|
||||||
|
InlineKeyboardButton("➕ Добавить", callback_data="server_add"),
|
||||||
|
InlineKeyboardButton("⬅️ Назад", callback_data="main")
|
||||||
|
])
|
||||||
|
|
||||||
state.current_menu = "server"
|
state.current_menu = "server"
|
||||||
await query.edit_message_text(
|
await query.edit_message_text(
|
||||||
"🖥️ *Выберите сервер:*\n\n"
|
"🖥️ *Управление серверами*\n\n"
|
||||||
"Команды будут выполняться на выбранном сервере через SSH.",
|
"Выберите сервер для подключения или добавьте новый.\n"
|
||||||
|
"⚙️ — редактировать/удалить сервер",
|
||||||
parse_mode="Markdown",
|
parse_mode="Markdown",
|
||||||
reply_markup=InlineKeyboardMarkup(keyboard)
|
reply_markup=InlineKeyboardMarkup(keyboard)
|
||||||
)
|
)
|
||||||
|
|
||||||
elif callback == "server_add":
|
elif callback == "server_add":
|
||||||
|
state.waiting_for_input = True
|
||||||
|
state.input_type = "add_server_name"
|
||||||
|
state.context["new_server"] = {}
|
||||||
await query.edit_message_text(
|
await query.edit_message_text(
|
||||||
"➕ *Добавление сервера*\n\n"
|
"➕ *Добавление сервера*\n\n"
|
||||||
"Для добавления сервера отредактируйте `.env`:\n"
|
"Введите *имя сервера* (латиница, без пробелов):\n"
|
||||||
"```\nSERVERS=name|host|port|user|tags\n```\n"
|
"Пример: `web-prod`, `db-backup`",
|
||||||
"Пример:\n"
|
|
||||||
"```\nSERVERS=web-prod|192.168.1.10|22|root|web,prod\n```\n"
|
|
||||||
"После изменения перезапустите бота.",
|
|
||||||
parse_mode="Markdown",
|
parse_mode="Markdown",
|
||||||
reply_markup=menu_builder.get_keyboard("server")
|
reply_markup=InlineKeyboardMarkup([[
|
||||||
|
InlineKeyboardButton("❌ Отмена", callback_data="server_menu")
|
||||||
|
]])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
elif callback.startswith("server_manage_"):
|
||||||
|
server_name = callback.replace("server_manage_", "")
|
||||||
|
server = server_manager.get(server_name)
|
||||||
|
|
||||||
|
if server and server_name != "local":
|
||||||
|
state.editing_server = server_name
|
||||||
|
await query.edit_message_text(
|
||||||
|
f"⚙️ *Управление сервером*\n\n"
|
||||||
|
f"{server.display_name}\n"
|
||||||
|
f"📍 `{server.description}`\n"
|
||||||
|
f"🏷️ Теги: `{','.join(server.tags) if server.tags else 'нет'}`\n\n"
|
||||||
|
f"Выберите действие:",
|
||||||
|
parse_mode="Markdown",
|
||||||
|
reply_markup=InlineKeyboardMarkup([
|
||||||
|
[InlineKeyboardButton("✏️ Редактировать", callback_data=f"server_edit_{server_name}")],
|
||||||
|
[InlineKeyboardButton("🗑️ Удалить", callback_data=f"server_delete_{server_name}")],
|
||||||
|
[InlineKeyboardButton("⬅️ Назад", callback_data="server_menu")]
|
||||||
|
])
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await query.edit_message_text(
|
||||||
|
f"❌ *Сервер не найден*\n\n"
|
||||||
|
f"Сервер `{server_name}` отсутствует в конфигурации.",
|
||||||
|
parse_mode="Markdown",
|
||||||
|
reply_markup=menu_builder.get_keyboard("server")
|
||||||
|
)
|
||||||
|
|
||||||
|
elif callback.startswith("server_edit_"):
|
||||||
|
server_name = callback.replace("server_edit_", "")
|
||||||
|
server = server_manager.get(server_name)
|
||||||
|
|
||||||
|
if server and server_name != "local":
|
||||||
|
state.editing_server = server_name
|
||||||
|
state.waiting_for_input = True
|
||||||
|
state.input_type = "edit_server_field"
|
||||||
|
await query.edit_message_text(
|
||||||
|
f"✏️ *Редактирование сервера: {server_name}*\n\n"
|
||||||
|
f"Текущие значения:\n"
|
||||||
|
f"• Host: `{server.host}`\n"
|
||||||
|
f"• Port: `{server.port}`\n"
|
||||||
|
f"• User: `{server.user}`\n"
|
||||||
|
f"• Tags: `{','.join(server.tags) if server.tags else 'нет'}`\n\n"
|
||||||
|
f"Введите номер поля для изменения:\n"
|
||||||
|
f"1 — Host\n"
|
||||||
|
f"2 — Port\n"
|
||||||
|
f"3 — User\n"
|
||||||
|
f"4 — Tags",
|
||||||
|
parse_mode="Markdown",
|
||||||
|
reply_markup=InlineKeyboardMarkup([[
|
||||||
|
InlineKeyboardButton("❌ Отмена", callback_data="server_menu")
|
||||||
|
]])
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await query.edit_message_text(
|
||||||
|
"❌ Ошибка: сервер не найден",
|
||||||
|
reply_markup=menu_builder.get_keyboard("server")
|
||||||
|
)
|
||||||
|
|
||||||
|
elif callback.startswith("server_delete_"):
|
||||||
|
server_name = callback.replace("server_delete_", "")
|
||||||
|
server = server_manager.get(server_name)
|
||||||
|
|
||||||
|
if server and server_name != "local":
|
||||||
|
# Удаляем сразу с подтверждением
|
||||||
|
if server_manager.delete_server(server_name):
|
||||||
|
await query.edit_message_text(
|
||||||
|
f"🗑️ *Сервер удалён*\n\n"
|
||||||
|
f"Сервер `{server_name}` успешно удалён из конфигурации.",
|
||||||
|
parse_mode="Markdown",
|
||||||
|
reply_markup=menu_builder.get_keyboard("server")
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await query.edit_message_text(
|
||||||
|
"❌ Ошибка при удалении сервера",
|
||||||
|
reply_markup=menu_builder.get_keyboard("server")
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await query.edit_message_text(
|
||||||
|
"❌ Нельзя удалить local сервер",
|
||||||
|
reply_markup=menu_builder.get_keyboard("server")
|
||||||
|
)
|
||||||
|
|
||||||
|
elif callback == "srv_skip_tags":
|
||||||
|
# Пропуск тегов при добавлении сервера
|
||||||
|
user_id = query.from_user.id
|
||||||
|
state = state_manager.get(user_id)
|
||||||
|
|
||||||
|
new_server = state.context.get("new_server", {})
|
||||||
|
if new_server.get("name") and new_server.get("host") and new_server.get("port") and new_server.get("user"):
|
||||||
|
if server_manager.add_server(
|
||||||
|
name=new_server["name"],
|
||||||
|
host=new_server["host"],
|
||||||
|
port=new_server["port"],
|
||||||
|
user=new_server["user"],
|
||||||
|
tags=[]
|
||||||
|
):
|
||||||
|
await query.edit_message_text(
|
||||||
|
"✅ *Сервер добавлен*\n\n"
|
||||||
|
f"Имя: `{new_server['name']}`\n"
|
||||||
|
f"Host: `{new_server['host']}`\n"
|
||||||
|
f"Port: `{new_server['port']}`\n"
|
||||||
|
f"User: `{new_server['user']}`\n"
|
||||||
|
f"Tags: нет\n\n"
|
||||||
|
f"Сервер сохранён в `.env` и доступен для выбора.",
|
||||||
|
parse_mode="Markdown",
|
||||||
|
reply_markup=menu_builder.get_keyboard("server")
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await query.edit_message_text(
|
||||||
|
"❌ Ошибка: сервер с таким именем уже существует",
|
||||||
|
reply_markup=menu_builder.get_keyboard("server")
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await query.edit_message_text(
|
||||||
|
"❌ Ошибка: неполные данные сервера",
|
||||||
|
reply_markup=menu_builder.get_keyboard("server")
|
||||||
|
)
|
||||||
|
|
||||||
|
state.waiting_for_input = False
|
||||||
|
state.input_type = None
|
||||||
|
state.context.clear()
|
||||||
|
|
||||||
elif callback.startswith("server_select_"):
|
elif callback.startswith("server_select_"):
|
||||||
server_name = callback.replace("server_select_", "")
|
server_name = callback.replace("server_select_", "")
|
||||||
server = server_manager.get(server_name)
|
server = server_manager.get(server_name)
|
||||||
|
|
@ -872,6 +1080,11 @@ async def handle_text_message(update: Update, context: ContextTypes.DEFAULT_TYPE
|
||||||
text = update.message.text.strip()
|
text = update.message.text.strip()
|
||||||
state = state_manager.get(user_id)
|
state = state_manager.get(user_id)
|
||||||
|
|
||||||
|
# Проверка: не в режиме ввода данных сервера ли мы
|
||||||
|
if state.waiting_for_input:
|
||||||
|
await handle_server_input(update, text)
|
||||||
|
return
|
||||||
|
|
||||||
# Любое текстовое сообщение = CLI команда
|
# Любое текстовое сообщение = CLI команда
|
||||||
logger.info(f"Пользователь {user_id} отправил команду: {text}")
|
logger.info(f"Пользователь {user_id} отправил команду: {text}")
|
||||||
|
|
||||||
|
|
@ -882,6 +1095,222 @@ async def handle_text_message(update: Update, context: ContextTypes.DEFAULT_TYPE
|
||||||
await execute_cli_command_from_message(update, text)
|
await execute_cli_command_from_message(update, text)
|
||||||
|
|
||||||
|
|
||||||
|
async def handle_server_input(update: Update, text: str):
|
||||||
|
"""Обработка ввода данных для CRUD операций с серверами."""
|
||||||
|
user_id = update.effective_user.id
|
||||||
|
state = state_manager.get(user_id)
|
||||||
|
input_type = state.input_type
|
||||||
|
|
||||||
|
if input_type == "add_server_name":
|
||||||
|
# Проверка имени
|
||||||
|
if not text.replace("-", "").replace("_", "").isalnum():
|
||||||
|
await update.message.reply_text(
|
||||||
|
"❌ Неверный формат имени.\n\n"
|
||||||
|
"Используйте только латиницу, дефисы и подчёркивания.\n"
|
||||||
|
"Пример: `web-prod`, `db_backup`",
|
||||||
|
parse_mode="Markdown",
|
||||||
|
reply_markup=InlineKeyboardMarkup([[
|
||||||
|
InlineKeyboardButton("❌ Отмена", callback_data="server_menu")
|
||||||
|
]])
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
state.context["new_server"]["name"] = text
|
||||||
|
state.input_type = "add_server_host"
|
||||||
|
await update.message.reply_text(
|
||||||
|
f"✅ Имя: `{text}`\n\n"
|
||||||
|
"Введите *host* (IP или домен):\n"
|
||||||
|
"Пример: `192.168.1.10`, `example.com`",
|
||||||
|
parse_mode="Markdown",
|
||||||
|
reply_markup=InlineKeyboardMarkup([[
|
||||||
|
InlineKeyboardButton("❌ Отмена", callback_data="server_menu")
|
||||||
|
]])
|
||||||
|
)
|
||||||
|
|
||||||
|
elif input_type == "add_server_host":
|
||||||
|
state.context["new_server"]["host"] = text
|
||||||
|
state.input_type = "add_server_port"
|
||||||
|
await update.message.reply_text(
|
||||||
|
f"✅ Host: `{text}`\n\n"
|
||||||
|
"Введите *SSH порт* (обычно 22):",
|
||||||
|
parse_mode="Markdown",
|
||||||
|
reply_markup=InlineKeyboardMarkup([[
|
||||||
|
InlineKeyboardButton("❌ Отмена", callback_data="server_menu")
|
||||||
|
]])
|
||||||
|
)
|
||||||
|
|
||||||
|
elif input_type == "add_server_port":
|
||||||
|
try:
|
||||||
|
port = int(text)
|
||||||
|
if port < 1 or port > 65535:
|
||||||
|
raise ValueError()
|
||||||
|
state.context["new_server"]["port"] = port
|
||||||
|
state.input_type = "add_server_user"
|
||||||
|
await update.message.reply_text(
|
||||||
|
f"✅ Port: `{port}`\n\n"
|
||||||
|
"Введите *SSH пользователя*:\n"
|
||||||
|
"Пример: `root`, `admin`, `ubuntu`",
|
||||||
|
parse_mode="Markdown",
|
||||||
|
reply_markup=InlineKeyboardMarkup([[
|
||||||
|
InlineKeyboardButton("❌ Отмена", callback_data="server_menu")
|
||||||
|
]])
|
||||||
|
)
|
||||||
|
except ValueError:
|
||||||
|
await update.message.reply_text(
|
||||||
|
"❌ Неверный формат порта.\n\n"
|
||||||
|
"Введите число от 1 до 65535:",
|
||||||
|
parse_mode="Markdown",
|
||||||
|
reply_markup=InlineKeyboardMarkup([[
|
||||||
|
InlineKeyboardButton("❌ Отмена", callback_data="server_menu")
|
||||||
|
]])
|
||||||
|
)
|
||||||
|
|
||||||
|
elif input_type == "add_server_user":
|
||||||
|
state.context["new_server"]["user"] = text
|
||||||
|
state.input_type = "add_server_tags"
|
||||||
|
await update.message.reply_text(
|
||||||
|
f"✅ User: `{text}`\n\n"
|
||||||
|
"Введите *теги* через запятую (или нажмите Пропустить):\n"
|
||||||
|
"Пример: `web,prod`, `db,backup`\n\n"
|
||||||
|
"Теги помогают группировать серверы.",
|
||||||
|
parse_mode="Markdown",
|
||||||
|
reply_markup=InlineKeyboardMarkup([
|
||||||
|
[InlineKeyboardButton("⏭️ Пропустить", callback_data="srv_skip_tags")],
|
||||||
|
[InlineKeyboardButton("❌ Отмена", callback_data="server_menu")]
|
||||||
|
])
|
||||||
|
)
|
||||||
|
|
||||||
|
elif input_type == "add_server_tags":
|
||||||
|
# Обработка ввода тегов (если пользователь ввёл текстом, а не нажал кнопку)
|
||||||
|
tags = [t.strip() for t in text.split(",") if t.strip()]
|
||||||
|
state.context["new_server"]["tags"] = tags
|
||||||
|
|
||||||
|
# Завершение добавления
|
||||||
|
new_server = state.context.get("new_server", {})
|
||||||
|
if server_manager.add_server(
|
||||||
|
name=new_server["name"],
|
||||||
|
host=new_server["host"],
|
||||||
|
port=new_server["port"],
|
||||||
|
user=new_server["user"],
|
||||||
|
tags=tags
|
||||||
|
):
|
||||||
|
await update.message.reply_text(
|
||||||
|
"✅ *Сервер добавлен*\n\n"
|
||||||
|
f"Имя: `{new_server['name']}`\n"
|
||||||
|
f"Host: `{new_server['host']}`\n"
|
||||||
|
f"Port: `{new_server['port']}`\n"
|
||||||
|
f"User: `{new_server['user']}`\n"
|
||||||
|
f"Tags: `{','.join(tags)}`\n\n"
|
||||||
|
f"Сервер сохранён в `.env` и доступен для выбора.",
|
||||||
|
parse_mode="Markdown",
|
||||||
|
reply_markup=menu_builder.get_keyboard("server")
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await update.message.reply_text(
|
||||||
|
"❌ Ошибка: сервер с таким именем уже существует",
|
||||||
|
reply_markup=menu_builder.get_keyboard("server")
|
||||||
|
)
|
||||||
|
|
||||||
|
state.waiting_for_input = False
|
||||||
|
state.input_type = None
|
||||||
|
state.context.clear()
|
||||||
|
|
||||||
|
elif input_type == "edit_server_field":
|
||||||
|
# Выбор поля для редактирования
|
||||||
|
if text == "1":
|
||||||
|
state.input_type = "edit_server_host"
|
||||||
|
await update.message.reply_text(
|
||||||
|
"Введите новый *host*:",
|
||||||
|
parse_mode="Markdown"
|
||||||
|
)
|
||||||
|
elif text == "2":
|
||||||
|
state.input_type = "edit_server_port"
|
||||||
|
await update.message.reply_text(
|
||||||
|
"Введите новый *port*:",
|
||||||
|
parse_mode="Markdown"
|
||||||
|
)
|
||||||
|
elif text == "3":
|
||||||
|
state.input_type = "edit_server_user"
|
||||||
|
await update.message.reply_text(
|
||||||
|
"Введите нового *user*:",
|
||||||
|
parse_mode="Markdown"
|
||||||
|
)
|
||||||
|
elif text == "4":
|
||||||
|
state.input_type = "edit_server_tags"
|
||||||
|
await update.message.reply_text(
|
||||||
|
"Введите новые *теги* через запятую:",
|
||||||
|
parse_mode="Markdown"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await update.message.reply_text(
|
||||||
|
"❌ Введите номер поля (1-4):",
|
||||||
|
reply_markup=InlineKeyboardMarkup([[
|
||||||
|
InlineKeyboardButton("❌ Отмена", callback_data="server_menu")
|
||||||
|
]])
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
elif input_type == "edit_server_host":
|
||||||
|
server_manager.update_server(state.editing_server, host=text)
|
||||||
|
await finish_edit_server(update, state)
|
||||||
|
|
||||||
|
elif input_type == "edit_server_port":
|
||||||
|
try:
|
||||||
|
port = int(text)
|
||||||
|
server_manager.update_server(state.editing_server, port=port)
|
||||||
|
await finish_edit_server(update, state)
|
||||||
|
except ValueError:
|
||||||
|
await update.message.reply_text("❌ Неверный формат порта")
|
||||||
|
return
|
||||||
|
|
||||||
|
elif input_type == "edit_server_user":
|
||||||
|
server_manager.update_server(state.editing_server, user=text)
|
||||||
|
await finish_edit_server(update, state)
|
||||||
|
|
||||||
|
elif input_type == "edit_server_tags":
|
||||||
|
tags = [t.strip() for t in text.split(",") if t.strip()]
|
||||||
|
server_manager.update_server(state.editing_server, tags=tags)
|
||||||
|
await finish_edit_server(update, state)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Неизвестный тип ввода - выполняем команду
|
||||||
|
await update.message.reply_text(
|
||||||
|
f"⏳ *Выполнение...*\n\n`{text}`",
|
||||||
|
parse_mode="Markdown"
|
||||||
|
)
|
||||||
|
await execute_cli_command_from_message(update, text)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Сброс состояния после завершения
|
||||||
|
if not state.waiting_for_input or input_type.startswith("add_server_tags"):
|
||||||
|
state.waiting_for_input = False
|
||||||
|
state.input_type = None
|
||||||
|
state.context.clear()
|
||||||
|
|
||||||
|
|
||||||
|
async def finish_edit_server(update: Update, state):
|
||||||
|
"""Завершение редактирования сервера."""
|
||||||
|
server_name = state.editing_server
|
||||||
|
state.waiting_for_input = False
|
||||||
|
state.input_type = None
|
||||||
|
state.editing_server = None
|
||||||
|
|
||||||
|
server = server_manager.get(server_name)
|
||||||
|
if server:
|
||||||
|
await update.message.reply_text(
|
||||||
|
"✅ *Сервер обновлён*\n\n"
|
||||||
|
f"{server.display_name}\n"
|
||||||
|
f"📍 `{server.description}`",
|
||||||
|
parse_mode="Markdown",
|
||||||
|
reply_markup=menu_builder.get_keyboard("server")
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await update.message.reply_text(
|
||||||
|
"❌ Ошибка при обновлении сервера",
|
||||||
|
reply_markup=menu_builder.get_keyboard("server")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def execute_cli_command_from_message(update: Update, command: str):
|
async def execute_cli_command_from_message(update: Update, command: str):
|
||||||
"""Выполнение CLI команды из сообщения."""
|
"""Выполнение CLI команды из сообщения."""
|
||||||
user_id = update.effective_user.id
|
user_id = update.effective_user.id
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue