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:
@@ -47,8 +47,19 @@ async def update_config(
|
||||
from src.config.settings import settings as app_settings
|
||||
|
||||
anime_dir_changed = False
|
||||
if update.other and update.other.get("anime_directory"):
|
||||
anime_dir = update.other.get("anime_directory")
|
||||
other_data = update.other
|
||||
if isinstance(other_data, str):
|
||||
try:
|
||||
import ast
|
||||
other_data = ast.literal_eval(other_data)
|
||||
except (ValueError, SyntaxError):
|
||||
try:
|
||||
import json
|
||||
other_data = json.loads(other_data)
|
||||
except (ValueError, json.JSONDecodeError):
|
||||
other_data = None
|
||||
if other_data and other_data.get("anime_directory"):
|
||||
anime_dir = other_data.get("anime_directory")
|
||||
if anime_dir and not app_settings.anime_directory:
|
||||
app_settings.anime_directory = str(anime_dir)
|
||||
anime_dir_changed = True
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user