import logging
from aiogram import Dispatcher, types, F
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
from sqlalchemy.ext.asyncio import AsyncSession
from app.config import settings
from app.database.models import User
from app.services.version_service import version_service
from app.utils.decorators import admin_required, error_handler
logger = logging.getLogger(__name__)
def get_updates_keyboard(language: str = "ru") -> InlineKeyboardMarkup:
buttons = [
[
InlineKeyboardButton(
text="🔄 Проверить обновления",
callback_data="admin_updates_check"
)
],
[
InlineKeyboardButton(
text="📋 Информация о версии",
callback_data="admin_updates_info"
)
],
[
InlineKeyboardButton(
text="🔗 Открыть репозиторий",
url=f"https://github.com/{version_service.repo}/releases"
)
],
[
InlineKeyboardButton(
text="◀️ Назад",
callback_data="admin_panel"
)
]
]
return InlineKeyboardMarkup(inline_keyboard=buttons)
def get_version_info_keyboard(language: str = "ru") -> InlineKeyboardMarkup:
buttons = [
[
InlineKeyboardButton(
text="🔄 Обновить",
callback_data="admin_updates_info"
)
],
[
InlineKeyboardButton(
text="◀️ К обновлениям",
callback_data="admin_updates"
)
]
]
return InlineKeyboardMarkup(inline_keyboard=buttons)
@admin_required
@error_handler
async def show_updates_menu(
callback: types.CallbackQuery,
db_user: User,
db: AsyncSession
):
try:
version_info = await version_service.get_version_info()
current_version = version_info['current_version']
has_updates = version_info['has_updates']
total_newer = version_info['total_newer']
last_check = version_info['last_check']
status_icon = "🆕" if has_updates else "✅"
status_text = f"Доступно {total_newer} обновлений" if has_updates else "Актуальная версия"
last_check_text = ""
if last_check:
last_check_text = f"\n🕐 Последняя проверка: {last_check.strftime('%d.%m.%Y %H:%M')}"
message = f"""🔄 СИСТЕМА ОБНОВЛЕНИЙ
📦 Текущая версия: {current_version}
{status_icon} Статус: {status_text}
🔗 Репозиторий: {version_service.repo}{last_check_text}
ℹ️ Система автоматически проверяет обновления каждый час и отправляет уведомления о новых версиях."""
await callback.message.edit_text(
message,
reply_markup=get_updates_keyboard(db_user.language),
parse_mode="HTML"
)
await callback.answer()
except Exception as e:
logger.error(f"Ошибка показа меню обновлений: {e}")
await callback.answer("❌ Ошибка загрузки меню обновлений", show_alert=True)
@admin_required
@error_handler
async def check_updates(
callback: types.CallbackQuery,
db_user: User,
db: AsyncSession
):
await callback.answer("🔄 Проверяю обновления...")
try:
has_updates, newer_releases = await version_service.check_for_updates(force=True)
if not has_updates:
message = f"""✅ ОБНОВЛЕНИЯ НЕ НАЙДЕНЫ
📦 Текущая версия: {version_service.current_version}
🎯 Статус: У вас установлена последняя версия
🔗 Репозиторий: {version_service.repo}"""
else:
updates_list = []
for i, release in enumerate(newer_releases[:5]):
icon = version_service.format_version_display(release).split()[0]
updates_list.append(
f"{i+1}. {icon} {release.tag_name} • {release.formatted_date}"
)
updates_text = "\n".join(updates_list)
more_text = f"\n\n📋 И еще {len(newer_releases) - 5} обновлений..." if len(newer_releases) > 5 else ""
message = f"""🆕 НАЙДЕНЫ ОБНОВЛЕНИЯ
📦 Текущая версия: {version_service.current_version}
🎯 Доступно обновлений: {len(newer_releases)}
📋 Последние версии:
{updates_text}{more_text}
🔗 Репозиторий: {version_service.repo}"""
keyboard = get_updates_keyboard(db_user.language)
if has_updates:
keyboard.inline_keyboard.insert(-2, [
InlineKeyboardButton(
text="📋 Подробнее о версиях",
callback_data="admin_updates_info"
)
])
await callback.message.edit_text(
message,
reply_markup=keyboard,
parse_mode="HTML"
)
except Exception as e:
logger.error(f"Ошибка проверки обновлений: {e}")
await callback.message.edit_text(
f"❌ ОШИБКА ПРОВЕРКИ ОБНОВЛЕНИЙ\n\n"
f"Не удалось связаться с сервером GitHub.\n"
f"Попробуйте позже.\n\n"
f"📦 Текущая версия: {version_service.current_version}",
reply_markup=get_updates_keyboard(db_user.language),
parse_mode="HTML"
)
@admin_required
@error_handler
async def show_version_info(
callback: types.CallbackQuery,
db_user: User,
db: AsyncSession
):
await callback.answer("📋 Загружаю информацию о версиях...")
try:
version_info = await version_service.get_version_info()
current_version = version_info['current_version']
current_release = version_info['current_release']
newer_releases = version_info['newer_releases']
has_updates = version_info['has_updates']
last_check = version_info['last_check']
repo_url = version_info['repo_url']
current_info = f"📦 ТЕКУЩАЯ ВЕРСИЯ\n\n"
if current_release:
current_info += f"🏷️ Версия: {current_release.tag_name}\n"
current_info += f"📅 Дата релиза: {current_release.formatted_date}\n"
if current_release.short_description:
current_info += f"📝 Описание:\n{current_release.short_description}\n"
else:
current_info += f"🏷️ Версия: {current_version}\n"
current_info += f"ℹ️ Статус: Информация о релизе недоступна\n"
message_parts = [current_info]
if has_updates and newer_releases:
updates_info = f"\n🆕 ДОСТУПНЫЕ ОБНОВЛЕНИЯ\n\n"
for i, release in enumerate(newer_releases):
icon = "🔥" if i == 0 else "📦"
if release.prerelease:
icon = "🧪"
elif release.is_dev:
icon = "🔧"
updates_info += f"{icon} {release.tag_name}\n"
updates_info += f" 📅 {release.formatted_date}\n"
if release.short_description:
updates_info += f" 📝 {release.short_description}\n"
updates_info += "\n"
message_parts.append(updates_info.rstrip())
system_info = f"\n🔧 СИСТЕМА ОБНОВЛЕНИЙ\n\n"
system_info += f"🔗 Репозиторий: {version_service.repo}\n"
system_info += f"⚡ Автопроверка: {'Включена' if version_service.enabled else 'Отключена'}\n"
system_info += f"🕐 Интервал: Каждый час\n"
if last_check:
system_info += f"🕐 Последняя проверка: {last_check.strftime('%d.%m.%Y %H:%M')}\n"
message_parts.append(system_info.rstrip())
final_message = "\n".join(message_parts)
if len(final_message) > 4000:
final_message = final_message[:3900] + "\n\n... (информация обрезана)"
await callback.message.edit_text(
final_message,
reply_markup=get_version_info_keyboard(db_user.language),
parse_mode="HTML",
disable_web_page_preview=True
)
except Exception as e:
logger.error(f"Ошибка получения информации о версиях: {e}")
await callback.message.edit_text(
f"❌ ОШИБКА ЗАГРУЗКИ\n\n"
f"Не удалось получить информацию о версиях.\n\n"
f"📦 Текущая версия: {version_service.current_version}",
reply_markup=get_version_info_keyboard(db_user.language),
parse_mode="HTML"
)
def register_handlers(dp: Dispatcher):
dp.callback_query.register(
show_updates_menu,
F.data == "admin_updates"
)
dp.callback_query.register(
check_updates,
F.data == "admin_updates_check"
)
dp.callback_query.register(
show_version_info,
F.data == "admin_updates_info"
)