115 lines
4.7 KiB
Python
115 lines
4.7 KiB
Python
import os
|
|
|
|
from aiogram import F
|
|
from aiogram.fsm.context import FSMContext
|
|
from aiogram.fsm.state import State, StatesGroup
|
|
from aiogram.types import CallbackQuery, Message
|
|
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
|
|
|
from core.executor import run_io
|
|
from filters.admin import HasPermission
|
|
from filters.permissions import PERM_MANAGEMENT
|
|
from logger import logger
|
|
|
|
from ..panel.keyboard import build_admin_back_kb
|
|
from . import router
|
|
from .keyboard import AdminPanelCallback
|
|
|
|
|
|
class FileUploadState(StatesGroup):
|
|
waiting_for_target = State()
|
|
waiting_for_file = State()
|
|
|
|
|
|
@router.callback_query(AdminPanelCallback.filter(F.action == "upload_file"), HasPermission(PERM_MANAGEMENT))
|
|
async def prompt_for_file_upload(callback: CallbackQuery, state: FSMContext):
|
|
text = (
|
|
"📤 <b>Загрузка файла</b>\n\n"
|
|
"Вы можете заменить файл в корневой директории бота или в папке <code>handlers</code>.\n\n"
|
|
"📁 Выберите директорию, а затем отправьте файл с таким же именем и расширением, "
|
|
"как у уже существующего файла. Он будет автоматически заменён."
|
|
)
|
|
|
|
back_kb = build_admin_back_kb("management")
|
|
kb = InlineKeyboardBuilder()
|
|
kb.button(text="📁 Корень бота", callback_data="upload_target:root")
|
|
kb.button(text="📂 Папка handlers", callback_data="upload_target:handlers")
|
|
for row in back_kb.inline_keyboard:
|
|
kb.row(*row)
|
|
|
|
await callback.message.edit_text(
|
|
text,
|
|
reply_markup=kb.as_markup(),
|
|
)
|
|
await state.set_state(FileUploadState.waiting_for_target)
|
|
|
|
|
|
@router.callback_query(F.data.startswith("upload_target:"), FileUploadState.waiting_for_target, HasPermission(PERM_MANAGEMENT))
|
|
async def select_upload_target(callback: CallbackQuery, state: FSMContext):
|
|
target = callback.data.split(":", 1)[1]
|
|
if target not in {"root", "handlers"}:
|
|
await callback.answer("Неизвестная директория.")
|
|
return
|
|
|
|
await state.update_data(upload_target=target)
|
|
|
|
target_text = "Корень бота" if target == "root" else "Папка handlers"
|
|
await callback.message.edit_text(
|
|
"📤 <b>Загрузка файла</b>\n\n"
|
|
f"Выбрана директория: <b>{target_text}</b>.\n\n"
|
|
"Теперь отправьте файл с таким же именем и расширением, как у уже существующего файла. "
|
|
"Он будет автоматически заменён.",
|
|
reply_markup=build_admin_back_kb("management"),
|
|
)
|
|
await state.set_state(FileUploadState.waiting_for_file)
|
|
|
|
|
|
@router.message(FileUploadState.waiting_for_file, F.document, HasPermission(PERM_MANAGEMENT))
|
|
async def handle_admin_file_upload(message: Message, state: FSMContext):
|
|
document = message.document
|
|
file_name = document.file_name
|
|
|
|
if not file_name or "." not in file_name:
|
|
await message.answer("❌ У файла должно быть имя с расширением.")
|
|
return
|
|
|
|
data = await state.get_data()
|
|
target = data.get("upload_target", "root")
|
|
|
|
if target == "handlers":
|
|
base_dir = os.path.abspath("./handlers")
|
|
else:
|
|
base_dir = os.path.abspath(".")
|
|
|
|
await run_io(lambda: os.makedirs(base_dir, exist_ok=True))
|
|
safe_name = os.path.basename(file_name)
|
|
dest_path = os.path.join(base_dir, safe_name)
|
|
if not os.path.abspath(dest_path).startswith(base_dir + os.sep):
|
|
await message.answer("❌ Недопустимое имя файла.")
|
|
return
|
|
|
|
try:
|
|
await message.bot.download(document, destination=dest_path)
|
|
|
|
back_kb = build_admin_back_kb("management")
|
|
kb = InlineKeyboardBuilder()
|
|
kb.button(
|
|
text="🔁 Перезагрузить бота",
|
|
callback_data=AdminPanelCallback(action="restart").pack(),
|
|
)
|
|
for row in back_kb.inline_keyboard:
|
|
kb.row(*row)
|
|
|
|
await message.answer(
|
|
f"✅ Файл <code>{file_name}</code> успешно загружен и заменён в директории <code>{target}</code>.\n\n"
|
|
"🔄 <b>Перезагрузите бота, чтобы изменения вступили в силу.</b>",
|
|
reply_markup=kb.as_markup(),
|
|
)
|
|
except Exception as e:
|
|
logger.error(f"[Upload File] Ошибка при загрузке файла {file_name}: {e}")
|
|
await message.answer(
|
|
f"❌ Не удалось сохранить файл: {e}",
|
|
reply_markup=build_admin_back_kb("management"),
|
|
)
|
|
await state.clear()
|