Files
NexaPG/backend/app/api/routes/service_info.py
nessi bd53bce231
All checks were successful
PostgreSQL Compatibility Matrix / PG14 smoke (push) Successful in 9s
PostgreSQL Compatibility Matrix / PG15 smoke (push) Successful in 8s
PostgreSQL Compatibility Matrix / PG16 smoke (push) Successful in 8s
PostgreSQL Compatibility Matrix / PG17 smoke (push) Successful in 8s
PostgreSQL Compatibility Matrix / PG18 smoke (push) Successful in 8s
Add service update notification and version check enhancements
Introduced a front-end mechanism to notify users of available service updates and enhanced the service info page to reflect update status dynamically. Removed backend audit log writes for version checks to streamline operations and improve performance. Updated styling to visually highlight update notifications.
2026-02-13 09:24:53 +01:00

95 lines
3.1 KiB
Python

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.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:
_ = user
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)
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,
)