mirror of
https://github.com/DRYTRIX/TimeTracker.git
synced 2026-05-23 06:40:53 -05:00
96955aee62
Add VersionService to fetch and cache the latest GitHub release, compare it to the installed semver (APP_VERSION when valid, else setup.py), and expose admin-only GET /api/version/check and POST /api/version/dismiss on the legacy /api blueprint (session or Bearer token). Persist per-user dismissal in users.dismissed_release_version (Alembic 148) and show a non-blocking update card in base.html for administrators. Add packaging for semver parsing and tests for comparison, service, and routes. Document configuration in docs/admin/deployment/VERSION_MANAGEMENT.md and endpoints in docs/api/REST_API.md and docs/API.md.
35 lines
973 B
Python
35 lines
973 B
Python
"""Semantic version helpers for release / update checks (uses packaging.version)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from packaging.version import InvalidVersion, Version
|
|
|
|
|
|
def normalize_version_tag(raw: str | None) -> str | None:
|
|
"""Strip whitespace and leading 'v'; return a normalized string if parseable as a Version, else None."""
|
|
if raw is None:
|
|
return None
|
|
s = raw.strip()
|
|
if not s:
|
|
return None
|
|
if s.lower().startswith("v"):
|
|
s = s[1:].strip()
|
|
if not s:
|
|
return None
|
|
try:
|
|
return str(Version(s))
|
|
except InvalidVersion:
|
|
return None
|
|
|
|
|
|
def is_upgrade(current: str | None, latest: str | None) -> bool:
|
|
"""True iff both are valid versions and latest is strictly greater than current."""
|
|
if not current or not latest:
|
|
return False
|
|
try:
|
|
vc = Version(current)
|
|
vl = Version(latest)
|
|
except InvalidVersion:
|
|
return False
|
|
return vl > vc
|