Files
Aniworld/src/server/database/system_settings_service.py
Lukas cbd53ef2a0 feat: add legacy key/data file migration to database
- Add migration_legacy_files_completed flag to SystemSettings model
- Create legacy_file_migration service to migrate series from key/data files
- Integrate legacy migration into initialization_service startup flow
- Add integration tests for legacy file migration
- Update DATABASE.md documentation with migration details
- Fix various test and service issues (nfo_repair, tmdb_client, download_service)
- Add test_database_schema unit tests
2026-05-26 17:44:42 +02:00

190 lines
6.3 KiB
Python

"""System settings service for managing application-level configuration.
This module provides services for managing system-wide settings and state,
including tracking initial setup completion status.
"""
from __future__ import annotations
from datetime import datetime, timezone
from typing import Optional
import structlog
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from src.server.database.models import SystemSettings
logger = structlog.get_logger(__name__)
class SystemSettingsService:
"""Service for managing system settings."""
@staticmethod
async def get_or_create(db: AsyncSession) -> SystemSettings:
"""Get the system settings record, creating it if it doesn't exist.
Only one system settings record should exist in the database.
Args:
db: Database session
Returns:
SystemSettings instance
"""
# Try to get existing settings
stmt = select(SystemSettings).limit(1)
result = await db.execute(stmt)
settings = result.scalar_one_or_none()
if settings is None:
# Create new settings with defaults
settings = SystemSettings(
initial_scan_completed=False,
initial_nfo_scan_completed=False,
initial_media_scan_completed=False,
)
db.add(settings)
await db.commit()
await db.refresh(settings)
logger.info("Created new system settings record")
return settings
@staticmethod
async def is_initial_scan_completed(db: AsyncSession) -> bool:
"""Check if the initial anime folder scan has been completed.
Args:
db: Database session
Returns:
True if initial scan is completed, False otherwise
"""
settings = await SystemSettingsService.get_or_create(db)
return settings.initial_scan_completed
@staticmethod
async def mark_initial_scan_completed(
db: AsyncSession,
timestamp: Optional[datetime] = None
) -> None:
"""Mark the initial anime folder scan as completed.
Args:
db: Database session
timestamp: Optional timestamp to set, defaults to current time
"""
settings = await SystemSettingsService.get_or_create(db)
settings.initial_scan_completed = True
settings.last_scan_timestamp = timestamp or datetime.now(timezone.utc)
await db.commit()
logger.info("Marked initial scan as completed")
@staticmethod
async def is_initial_nfo_scan_completed(db: AsyncSession) -> bool:
"""Check if the initial NFO scan has been completed.
Args:
db: Database session
Returns:
True if initial NFO scan is completed, False otherwise
"""
settings = await SystemSettingsService.get_or_create(db)
return settings.initial_nfo_scan_completed
@staticmethod
async def mark_initial_nfo_scan_completed(
db: AsyncSession,
timestamp: Optional[datetime] = None
) -> None:
"""Mark the initial NFO scan as completed.
Args:
db: Database session
timestamp: Optional timestamp to set, defaults to current time
"""
settings = await SystemSettingsService.get_or_create(db)
settings.initial_nfo_scan_completed = True
if timestamp:
settings.last_scan_timestamp = timestamp
await db.commit()
logger.info("Marked initial NFO scan as completed")
@staticmethod
async def is_initial_media_scan_completed(db: AsyncSession) -> bool:
"""Check if the initial media scan has been completed.
Args:
db: Database session
Returns:
True if initial media scan is completed, False otherwise
"""
settings = await SystemSettingsService.get_or_create(db)
return settings.initial_media_scan_completed
@staticmethod
async def is_migration_legacy_files_completed(db: AsyncSession) -> bool:
"""Check if legacy key/data file migration has been completed.
Args:
db: Database session
Returns:
True if legacy migration is completed, False otherwise
"""
settings = await SystemSettingsService.get_or_create(db)
return settings.migration_legacy_files_completed
@staticmethod
async def mark_migration_legacy_files_completed(
db: AsyncSession,
timestamp: Optional[datetime] = None
) -> None:
"""Mark the legacy key/data file migration as completed.
Args:
db: Database session
timestamp: Optional timestamp to set, defaults to current time
"""
settings = await SystemSettingsService.get_or_create(db)
settings.migration_legacy_files_completed = True
settings.last_scan_timestamp = timestamp or datetime.now(timezone.utc)
await db.commit()
logger.info("Marked legacy files migration as completed")
@staticmethod
async def mark_initial_media_scan_completed(
db: AsyncSession,
timestamp: Optional[datetime] = None
) -> None:
"""Mark the initial media scan as completed.
Args:
db: Database session
timestamp: Optional timestamp to set, defaults to current time
"""
settings = await SystemSettingsService.get_or_create(db)
settings.initial_media_scan_completed = True
if timestamp:
settings.last_scan_timestamp = timestamp
await db.commit()
logger.info("Marked initial media scan as completed")
@staticmethod
async def reset_all_scans(db: AsyncSession) -> None:
"""Reset all scan completion flags (for testing or re-setup).
Args:
db: Database session
"""
settings = await SystemSettingsService.get_or_create(db)
settings.initial_scan_completed = False
settings.initial_nfo_scan_completed = False
settings.initial_media_scan_completed = False
settings.last_scan_timestamp = None
await db.commit()
logger.info("Reset all scan completion flags")