fix config: handle stringified JSON in API requests

ConfigUpdate fields (scheduler, logging, backup, nfo, other) arrive as
strings from frontend. Parse JSON or ast.literal_eval before validation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-06-27 13:56:18 +02:00
parent 6c502e2014
commit fd84a18b30
2 changed files with 69 additions and 13 deletions

View File

@@ -1,4 +1,6 @@
from typing import Dict, List, Optional
import ast
import json
from typing import Any, Dict, List, Optional
from pydantic import BaseModel, Field, ValidationError, field_validator
@@ -244,12 +246,12 @@ class AppConfig(BaseModel):
class ConfigUpdate(BaseModel):
name: Optional[str] = None
data_dir: Optional[str] = None
scheduler: Optional[SchedulerConfig] = None
logging: Optional[LoggingConfig] = None
backup: Optional[BackupConfig] = None
nfo: Optional[NFOConfig] = None
scheduler: Optional[Any] = None
logging: Optional[Any] = None
backup: Optional[Any] = None
nfo: Optional[Any] = None
scan_key_overrides: Optional[Dict[str, str]] = None
other: Optional[Dict[str, object]] = None
other: Optional[Any] = None
def apply_to(self, current: AppConfig) -> AppConfig:
"""Return a new AppConfig with updates applied to the current config.
@@ -257,18 +259,61 @@ class ConfigUpdate(BaseModel):
Performs a shallow merge for `other`.
"""
data = current.model_dump()
if self.name is not None:
data["name"] = self.name
if self.data_dir is not None:
data["data_dir"] = self.data_dir
if self.scheduler is not None:
data["scheduler"] = self.scheduler.model_dump()
scheduler_data = self.scheduler
if isinstance(scheduler_data, str):
try:
scheduler_data = json.loads(scheduler_data)
except json.JSONDecodeError:
scheduler_data = ast.literal_eval(scheduler_data)
if isinstance(scheduler_data, dict):
scheduler_data = SchedulerConfig(**scheduler_data)
data["scheduler"] = scheduler_data.model_dump()
if self.logging is not None:
data["logging"] = self.logging.model_dump()
logging_data = self.logging
if isinstance(logging_data, str):
try:
logging_data = json.loads(logging_data)
except json.JSONDecodeError:
logging_data = ast.literal_eval(logging_data)
if isinstance(logging_data, dict):
logging_data = LoggingConfig(**logging_data)
data["logging"] = logging_data.model_dump()
if self.backup is not None:
data["backup"] = self.backup.model_dump()
backup_data = self.backup
if isinstance(backup_data, str):
try:
backup_data = json.loads(backup_data)
except json.JSONDecodeError:
backup_data = ast.literal_eval(backup_data)
if isinstance(backup_data, dict):
backup_data = BackupConfig(**backup_data)
data["backup"] = backup_data.model_dump()
if self.nfo is not None:
data["nfo"] = self.nfo.model_dump()
nfo_data = self.nfo
if isinstance(nfo_data, str):
try:
nfo_data = json.loads(nfo_data)
except json.JSONDecodeError:
nfo_data = ast.literal_eval(nfo_data)
if isinstance(nfo_data, dict):
nfo_data = NFOConfig(**nfo_data)
data["nfo"] = nfo_data.model_dump()
if self.scan_key_overrides is not None:
data["scan_key_overrides"] = self.scan_key_overrides
if self.other is not None:
merged = dict(current.other or {})
merged.update(self.other)
other_data = self.other
if isinstance(other_data, str):
try:
other_data = json.loads(other_data)
except json.JSONDecodeError:
other_data = ast.literal_eval(other_data)
if isinstance(other_data, dict):
merged.update(other_data)
data["other"] = merged
return AppConfig(**data)