From 30bb953dcd90f9274bc41d2dc1b6f647053d6701 Mon Sep 17 00:00:00 2001 From: Vladless Date: Wed, 28 May 2025 20:48:11 +0300 Subject: [PATCH] CLI 0.1.8/update tariff menu --- cli_launcher.py | 48 +++++++-------- handlers/admin/tariffs/tariffs_handler.py | 73 +++++++++++------------ 2 files changed, 59 insertions(+), 62 deletions(-) diff --git a/cli_launcher.py b/cli_launcher.py index 2e0026e6..34fef7ae 100755 --- a/cli_launcher.py +++ b/cli_launcher.py @@ -96,17 +96,17 @@ def install_rsync_if_needed(): os.system("sudo apt update && sudo apt install -y rsync") -def clean_project_dir_safe(update_buttons=False): +def clean_project_dir_safe(update_buttons=False, update_img=False): console.print("[yellow]🧹 Очистка проекта перед обновлением...[/yellow]") preserved_paths = { os.path.join(PROJECT_DIR, "config.py"), - os.path.join(PROJECT_DIR, "handlers", "buttons.py"), os.path.join(PROJECT_DIR, "handlers", "texts.py"), - os.path.join(PROJECT_DIR, "img"), } if not update_buttons: preserved_paths.add(os.path.join(PROJECT_DIR, "handlers", "buttons.py")) + if not update_img: + preserved_paths.add(os.path.join(PROJECT_DIR, "img")) for root, dirs, files in os.walk(PROJECT_DIR, topdown=False): for file in files: @@ -124,6 +124,8 @@ def clean_project_dir_safe(update_buttons=False): dir_path = os.path.join(root, dir) if os.path.abspath(dir_path) == os.path.join(PROJECT_DIR, "handlers"): continue + if not update_img and os.path.abspath(dir_path) == os.path.join(PROJECT_DIR, "img"): + continue try: os.rmdir(dir_path) except Exception: @@ -207,18 +209,15 @@ def update_from_beta(): else: console.print("[red]⚠️ Не удалось определить версии.[/red]") - if not Confirm.ask( - "[yellow]🔁 Подтвердите обновление Solobot с ветки DEV[/yellow]" - ): + if not Confirm.ask("[yellow]🔁 Подтвердите обновление Solobot с ветки DEV[/yellow]"): return console.print("[red]⚠️ ВНИМАНИЕ! Папка бота будет перезаписана![/red]") if not Confirm.ask("[red]❓ Продолжить обновление?[/red]"): return - update_buttons = Confirm.ask( - "[yellow]🔄 Обновлять файл buttons.py?[/yellow]", default=False - ) + update_buttons = Confirm.ask("[yellow]🔄 Обновлять файл buttons.py?[/yellow]", default=False) + update_img = Confirm.ask("[yellow]🖼 Обновлять папку img?[/yellow]", default=False) backup_project() install_git_if_needed() @@ -232,11 +231,13 @@ def update_from_beta(): return subprocess.run(["sudo", "rm", "-rf", os.path.join(PROJECT_DIR, "venv")]) - clean_project_dir_safe(update_buttons=update_buttons) + clean_project_dir_safe(update_buttons=update_buttons, update_img=update_img) - exclude_options = "--exclude=img" + exclude_options = "" + if not update_img: + exclude_options += "--exclude=img " if not update_buttons: - exclude_options += " --exclude=handlers/buttons.py" + exclude_options += "--exclude=handlers/buttons.py " subprocess.run(f"rsync -a {exclude_options} {TEMP_DIR}/ {PROJECT_DIR}/", shell=True) subprocess.run(["rm", "-rf", TEMP_DIR]) @@ -259,9 +260,8 @@ def update_from_release(): if not Confirm.ask("[red]❓ Вы точно хотите продолжить?[/red]"): return - update_buttons = Confirm.ask( - "[yellow]🔄 Обновлять файл buttons.py?[/yellow]", default=False - ) + update_buttons = Confirm.ask("[yellow]🔄 Обновлять файл buttons.py?[/yellow]", default=False) + update_img = Confirm.ask("[yellow]🖼 Обновлять папку img?[/yellow]", default=False) backup_project() install_git_if_needed() @@ -292,9 +292,7 @@ def update_from_release(): ): return - console.print( - f"[cyan]📥 Клонируем релиз {tag_name} во временную папку...[/cyan]" - ) + console.print(f"[cyan]📥 Клонируем релиз {tag_name} во временную папку...[/cyan]") subprocess.run(["rm", "-rf", TEMP_DIR]) subprocess.run( f"git clone --depth 1 --branch {tag_name} {GITHUB_REPO} {TEMP_DIR}", @@ -304,15 +302,15 @@ def update_from_release(): console.print("[red]⚠️ Начинается перезапись файлов бота![/red]") subprocess.run(["sudo", "rm", "-rf", os.path.join(PROJECT_DIR, "venv")]) - clean_project_dir_safe(update_buttons=update_buttons) + clean_project_dir_safe(update_buttons=update_buttons, update_img=update_img) - exclude_options = "--exclude=img" + exclude_options = "" + if not update_img: + exclude_options += "--exclude=img " if not update_buttons: - exclude_options += " --exclude=handlers/buttons.py" + exclude_options += "--exclude=handlers/buttons.py " - subprocess.run( - f"rsync -a {exclude_options} {TEMP_DIR}/ {PROJECT_DIR}/", shell=True - ) + subprocess.run(f"rsync -a {exclude_options} {TEMP_DIR}/ {PROJECT_DIR}/", shell=True) subprocess.run(["rm", "-rf", TEMP_DIR]) fix_permissions() @@ -350,7 +348,7 @@ def show_update_menu(): def show_menu(): table = Table( - title="Solobot CLI v0.1.7", title_style="bold magenta", header_style="bold blue" + title="Solobot CLI v0.1.8", title_style="bold magenta", header_style="bold blue" ) table.add_column("№", justify="center", style="cyan", no_wrap=True) table.add_column("Операция", style="white") diff --git a/handlers/admin/tariffs/tariffs_handler.py b/handlers/admin/tariffs/tariffs_handler.py index 70af9ff5..6d7d807e 100644 --- a/handlers/admin/tariffs/tariffs_handler.py +++ b/handlers/admin/tariffs/tariffs_handler.py @@ -314,26 +314,8 @@ async def view_tariff( await callback.message.edit_text("❌ Тариф не найден.") return - traffic_text = ( - f"{tariff.traffic_limit} ГБ" if tariff.traffic_limit else "Безлимит" - ) - device_text = ( - f"{tariff.device_limit}" if tariff.device_limit is not None else "Безлимит" - ) - - text = ( - f"📄 Тариф: {tariff.name}\n\n" - f"📁 Группа: {tariff.group_code}\n" - f"📅 Длительность: {tariff.duration_days} дней\n" - f"💰 Стоимость: {tariff.price_rub}₽\n" - f"📦 Трафик: {traffic_text}\n" - f"📱 Устройств: {device_text}\n" - f"{'✅ Активен' if tariff.is_active else '⛔ Отключен'}" - ) - - await callback.message.edit_text( - text, reply_markup=build_single_tariff_kb(tariff_id) - ) + text, markup = render_tariff_card(tariff) + await callback.message.edit_text(text=text, reply_markup=markup) @router.callback_query( @@ -452,9 +434,7 @@ async def apply_edit(message: Message, state: FSMContext, session: AsyncSession) num = int(value) if num < 0: raise ValueError - if field == "traffic_limit": - value = num if num > 0 else None - elif field == "device_limit": + if field in ["traffic_limit", "device_limit"]: value = num if num > 0 else None else: value = num @@ -467,29 +447,27 @@ async def apply_edit(message: Message, state: FSMContext, session: AsyncSession) await session.commit() await state.clear() - await message.answer("✅ Тариф успешно обновлён.") + + text, markup = render_tariff_card(tariff) + await message.answer(text=text, reply_markup=markup) @router.callback_query(F.data.startswith("toggle_active|"), IsAdminFilter()) -async def toggle_tariff_status(callback: CallbackQuery, session): +async def toggle_tariff_status(callback: CallbackQuery, session: AsyncSession): tariff_id = int(callback.data.split("|")[1]) - row = await session.fetchrow( - "SELECT is_active FROM tariffs WHERE id = $1", tariff_id - ) - if not row: + result = await session.execute(select(Tariff).where(Tariff.id == tariff_id)) + tariff = result.scalar_one_or_none() + + if not tariff: await callback.message.edit_text("❌ Тариф не найден.") return - new_status = not row["is_active"] - await session.execute( - "UPDATE tariffs SET is_active = $1, updated_at = NOW() WHERE id = $2", - new_status, - tariff_id, - ) + tariff.is_active = not tariff.is_active + await session.commit() - status_text = "✅ Тариф активирован." if new_status else "⛔ Тариф отключён." - await callback.message.edit_text(status_text) + text, markup = render_tariff_card(tariff) + await callback.message.edit_text(text=text, reply_markup=markup) @router.callback_query( @@ -505,3 +483,24 @@ async def start_tariff_creation_existing_group( f"📦 Добавление нового тарифа в группу {group_code}\n\n📝 Введите название тарифа:", reply_markup=build_cancel_kb(), ) + + +def render_tariff_card(tariff: Tariff) -> tuple[str, InlineKeyboardMarkup]: + traffic_text = ( + f"{tariff.traffic_limit} ГБ" if tariff.traffic_limit else "Безлимит" + ) + device_text = ( + f"{tariff.device_limit}" if tariff.device_limit is not None else "Безлимит" + ) + + text = ( + f"📄 Тариф: {tariff.name}\n\n" + f"📁 Группа: {tariff.group_code}\n" + f"📅 Длительность: {tariff.duration_days} дней\n" + f"💰 Стоимость: {tariff.price_rub}₽\n" + f"📦 Трафик: {traffic_text}\n" + f"📱 Устройств: {device_text}\n" + f"{'✅ Активен' if tariff.is_active else '⛔ Отключен'}" + ) + + return text, build_single_tariff_kb(tariff.id) \ No newline at end of file