CLI 0.1.8/update tariff menu
This commit is contained in:
+23
-25
@@ -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")
|
||||
|
||||
@@ -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"<b>📄 Тариф: {tariff.name}</b>\n\n"
|
||||
f"📁 Группа: <code>{tariff.group_code}</code>\n"
|
||||
f"📅 Длительность: <b>{tariff.duration_days} дней</b>\n"
|
||||
f"💰 Стоимость: <b>{tariff.price_rub}₽</b>\n"
|
||||
f"📦 Трафик: <b>{traffic_text}</b>\n"
|
||||
f"📱 Устройств: <b>{device_text}</b>\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"📦 Добавление нового тарифа в группу <code>{group_code}</code>\n\n📝 Введите <b>название тарифа</b>:",
|
||||
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"<b>📄 Тариф: {tariff.name}</b>\n\n"
|
||||
f"📁 Группа: <code>{tariff.group_code}</code>\n"
|
||||
f"📅 Длительность: <b>{tariff.duration_days} дней</b>\n"
|
||||
f"💰 Стоимость: <b>{tariff.price_rub}₽</b>\n"
|
||||
f"📦 Трафик: <b>{traffic_text}</b>\n"
|
||||
f"📱 Устройств: <b>{device_text}</b>\n"
|
||||
f"{'✅ Активен' if tariff.is_active else '⛔ Отключен'}"
|
||||
)
|
||||
|
||||
return text, build_single_tariff_kb(tariff.id)
|
||||
Reference in New Issue
Block a user