import os import platform from datetime import datetime, timezone from fastapi import APIRouter, Depends from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.core.config import get_settings from app.core.db import get_db from app.core.deps import get_current_user from app.models.models import ServiceInfoSettings, User from app.schemas.service_info import ServiceInfoCheckResult, ServiceInfoOut from app.services.audit import write_audit_log from app.services.service_info import ( UPSTREAM_REPO_WEB, fetch_latest_from_upstream, is_update_available, utcnow, ) router = APIRouter() settings = get_settings() service_started_at = datetime.now(timezone.utc) async def _get_or_create_service_settings(db: AsyncSession) -> ServiceInfoSettings: row = await db.scalar(select(ServiceInfoSettings).limit(1)) if row: return row row = ServiceInfoSettings(current_version=settings.app_version) db.add(row) await db.commit() await db.refresh(row) return row def _to_out(row: ServiceInfoSettings) -> ServiceInfoOut: uptime_seconds = int((utcnow() - service_started_at).total_seconds()) return ServiceInfoOut( app_name=settings.app_name, environment=settings.environment, api_prefix=settings.api_v1_prefix, app_version=settings.app_version, hostname=platform.node() or os.getenv("HOSTNAME", "unknown"), python_version=platform.python_version(), platform=platform.platform(), service_started_at=service_started_at, uptime_seconds=max(uptime_seconds, 0), update_source=UPSTREAM_REPO_WEB, latest_version=row.latest_version, latest_ref=(row.release_check_url or None), update_available=row.update_available, last_checked_at=row.last_checked_at, last_check_error=row.last_check_error, ) @router.get("/info", response_model=ServiceInfoOut) async def get_service_info( user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ) -> ServiceInfoOut: _ = user row = await _get_or_create_service_settings(db) return _to_out(row) @router.post("/info/check", response_model=ServiceInfoCheckResult) async def check_service_version( user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ) -> ServiceInfoCheckResult: row = await _get_or_create_service_settings(db) check_time = utcnow() latest, latest_ref, error = await fetch_latest_from_upstream() row.last_checked_at = check_time row.last_check_error = error if latest: row.latest_version = latest row.release_check_url = latest_ref row.update_available = is_update_available(settings.app_version, latest) else: row.update_available = False await db.commit() await db.refresh(row) await write_audit_log( db, "service.info.check", user.id, { "latest_version": row.latest_version, "latest_ref": row.release_check_url, "update_available": row.update_available, "last_check_error": row.last_check_error, }, ) return ServiceInfoCheckResult( latest_version=row.latest_version, latest_ref=(row.release_check_url or None), update_available=row.update_available, last_checked_at=row.last_checked_at or check_time, last_check_error=row.last_check_error, )