refactor: split admin/config.py into ai_config and db_config

This commit is contained in:
2026-04-19 17:10:56 +03:00
parent 239368e595
commit 8fcd4150e5
4 changed files with 79 additions and 61 deletions

View File

@@ -7,7 +7,7 @@ from slowapi.util import get_remote_address
from . import models from . import models
from .database import engine from .database import engine
from .routers import items, operations, users, auth, sync, categories from .routers import items, operations, users, auth, sync, categories
from .routers.admin import backups, config from .routers.admin import backups, ai_config, db_config
from .logger import log from .logger import log
from .scheduler import scheduler, sync_scheduler_config from .scheduler import scheduler, sync_scheduler_config
@@ -91,7 +91,8 @@ app.include_router(auth.router)
app.include_router(sync.router) app.include_router(sync.router)
app.include_router(categories.router) app.include_router(categories.router)
app.include_router(backups.router) app.include_router(backups.router)
app.include_router(config.router) app.include_router(ai_config.router)
app.include_router(db_config.router)
@app.on_event("startup") @app.on_event("startup")
def startup_event(): def startup_event():

View File

@@ -3,56 +3,16 @@ from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from ... import models, schemas, auth from ... import models, schemas, auth
from ...database import get_db, BASE_DIR from ...database import get_db, BASE_DIR
from ...scheduler import sync_scheduler_config
from ...config_manager import ConfigManager from ...config_manager import ConfigManager
router = APIRouter( router = APIRouter(
prefix="/admin/db", prefix="/admin/ai",
tags=["Admin Configuration"] tags=["Admin Configuration"]
) )
PROJECT_ROOT = os.path.dirname(BASE_DIR) PROJECT_ROOT = os.path.dirname(BASE_DIR)
PROMPT_FILE_PATH = os.path.join(PROJECT_ROOT, "config", "ai_prompt.md") PROMPT_FILE_PATH = os.path.join(PROJECT_ROOT, "config", "ai_prompt.md")
@router.get("/settings", response_model=schemas.DbSettingsUpdate)
def get_db_settings(
db: Session = Depends(get_db),
current_admin: auth.TokenData = Depends(auth.get_current_admin)
):
"""Get database retention and scheduling settings."""
retention = db.query(models.SystemSetting).filter(models.SystemSetting.key == "backup_retention_count").first()
hour = db.query(models.SystemSetting).filter(models.SystemSetting.key == "backup_schedule_hour").first()
freq = db.query(models.SystemSetting).filter(models.SystemSetting.key == "backup_schedule_freq_days").first()
return {
"retention_count": int(retention.value) if retention else 10,
"schedule_hour": int(hour.value) if hour else 3,
"schedule_freq_days": int(freq.value) if freq else 1
}
@router.patch("/settings", response_model=schemas.DbSettingsUpdate)
def update_db_settings(
settings: schemas.DbSettingsUpdate,
db: Session = Depends(get_db),
current_admin: auth.TokenData = Depends(auth.get_current_admin)
):
"""Update database settings and re-trigger scheduler sync."""
pairs = {
"backup_retention_count": str(settings.retention_count),
"backup_schedule_hour": str(settings.schedule_hour),
"backup_schedule_freq_days": str(settings.schedule_freq_days)
}
for key, val in pairs.items():
existing = db.query(models.SystemSetting).filter(models.SystemSetting.key == key).first()
if existing:
existing.value = val
else:
db.add(models.SystemSetting(key=key, value=val))
db.commit()
sync_scheduler_config()
return settings
@router.get("/settings/prompt") @router.get("/settings/prompt")
def get_ai_prompt( def get_ai_prompt(
@@ -72,6 +32,7 @@ def get_ai_prompt(
return {"value": "", "source": "none"} return {"value": "", "source": "none"}
return {"value": setting.value, "source": "database"} return {"value": setting.value, "source": "database"}
@router.post("/settings/prompt") @router.post("/settings/prompt")
def update_ai_prompt( def update_ai_prompt(
payload: dict, payload: dict,
@@ -99,7 +60,8 @@ def update_ai_prompt(
db.commit() db.commit()
return {"status": "success", "file_updated": os.path.exists(PROMPT_FILE_PATH)} return {"status": "success", "file_updated": os.path.exists(PROMPT_FILE_PATH)}
@router.get("/settings/ai")
@router.get("/settings")
def get_ai_config( def get_ai_config(
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_admin: auth.TokenData = Depends(auth.get_current_admin) current_admin: auth.TokenData = Depends(auth.get_current_admin)
@@ -131,7 +93,8 @@ def get_ai_config(
] ]
} }
@router.post("/settings/ai-keys")
@router.post("/settings/keys")
def update_ai_keys( def update_ai_keys(
payload: dict, payload: dict,
current_admin: auth.TokenData = Depends(auth.get_current_admin) current_admin: auth.TokenData = Depends(auth.get_current_admin)
@@ -155,7 +118,8 @@ def update_ai_keys(
"claude_configured": bool(os.environ.get("CLAUDE_API_KEY")) "claude_configured": bool(os.environ.get("CLAUDE_API_KEY"))
} }
@router.post("/settings/test-ai-key")
@router.post("/settings/test-key")
def test_ai_key( def test_ai_key(
payload: dict, payload: dict,
current_admin: auth.TokenData = Depends(auth.get_current_admin) current_admin: auth.TokenData = Depends(auth.get_current_admin)
@@ -187,7 +151,8 @@ def test_ai_key(
except Exception as e: except Exception as e:
raise HTTPException(status_code=400, detail=f"{provider.capitalize()} Test Failed: {str(e)}") raise HTTPException(status_code=400, detail=f"{provider.capitalize()} Test Failed: {str(e)}")
@router.post("/settings/ai")
@router.post("/settings")
def update_ai_provider( def update_ai_provider(
payload: dict, payload: dict,
db: Session = Depends(get_db), db: Session = Depends(get_db),

View File

@@ -0,0 +1,52 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from ... import models, schemas, auth
from ...database import get_db
from ...scheduler import sync_scheduler_config
router = APIRouter(
prefix="/admin/db",
tags=["Admin Configuration"]
)
@router.get("/settings", response_model=schemas.DbSettingsUpdate)
def get_db_settings(
db: Session = Depends(get_db),
current_admin: auth.TokenData = Depends(auth.get_current_admin)
):
"""Get database retention and scheduling settings."""
retention = db.query(models.SystemSetting).filter(models.SystemSetting.key == "backup_retention_count").first()
hour = db.query(models.SystemSetting).filter(models.SystemSetting.key == "backup_schedule_hour").first()
freq = db.query(models.SystemSetting).filter(models.SystemSetting.key == "backup_schedule_freq_days").first()
return {
"retention_count": int(retention.value) if retention else 10,
"schedule_hour": int(hour.value) if hour else 3,
"schedule_freq_days": int(freq.value) if freq else 1
}
@router.patch("/settings", response_model=schemas.DbSettingsUpdate)
def update_db_settings(
settings: schemas.DbSettingsUpdate,
db: Session = Depends(get_db),
current_admin: auth.TokenData = Depends(auth.get_current_admin)
):
"""Update database settings and re-trigger scheduler sync."""
pairs = {
"backup_retention_count": str(settings.retention_count),
"backup_schedule_hour": str(settings.schedule_hour),
"backup_schedule_freq_days": str(settings.schedule_freq_days)
}
for key, val in pairs.items():
existing = db.query(models.SystemSetting).filter(models.SystemSetting.key == key).first()
if existing:
existing.value = val
else:
db.add(models.SystemSetting(key=key, value=val))
db.commit()
sync_scheduler_config()
return settings

View File

@@ -38,7 +38,7 @@ def test_db_settings_workflow(test_client, admin_token):
def test_ai_config(test_client, admin_token): def test_ai_config(test_client, admin_token):
response = test_client.get( response = test_client.get(
"/admin/db/settings/ai", "/admin/ai/settings",
headers={"Authorization": f"Bearer {admin_token}"} headers={"Authorization": f"Bearer {admin_token}"}
) )
assert response.status_code == status.HTTP_200_OK assert response.status_code == status.HTTP_200_OK