Files
orc-order-v2/web/backend/routers/config_api.py
T
houhuan dedc3b4183 feat: complete web application — FastAPI backend + Vue 3 SPA frontend
- Full FastAPI backend with JWT auth, file management, processing pipeline,
  memory CRUD, barcode mappings, config management, cloud sync
- Vue 3 + Element Plus frontend with dashboard, task history, HTTP logs,
  memory editor, barcode editor, config editor, sync page
- HTTP request logging middleware with SQLite persistence
- Task history tracking with progress and retry support
- File metadata recording for upload/download operations
- WebAuth section in config.ini for bcrypt password storage
- Bug fix: logs.py count query returns tuple not dict

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-05 11:59:07 +08:00

99 lines
2.7 KiB
Python

"""Configuration read/write endpoints."""
from typing import Dict, Optional, Any
from fastapi import APIRouter, HTTPException, Depends
from pydantic import BaseModel
from ..auth.dependencies import get_current_user
router = APIRouter(prefix="/api/config", tags=["config"])
# Keys that should be masked in GET responses
_SENSITIVE_KEYS = {"api_key", "secret_key", "token", "password", "api_secret", "access_key"}
# Sections to expose (match actual config.ini)
_ALLOWED_SECTIONS = {"API", "Paths", "Performance", "File", "Templates", "Gitea", "WebAuth"}
class ConfigUpdate(BaseModel):
section: str
key: str
value: str
class ConfigBulkUpdate(BaseModel):
updates: list[ConfigUpdate]
def _get_config():
from app.config.settings import ConfigManager
return ConfigManager()
def _mask_value(key: str, value: str) -> str:
if any(s in key.lower() for s in _SENSITIVE_KEYS):
if len(value) > 4:
return value[:2] + "*" * (len(value) - 4) + value[-2:]
return "****"
return value
@router.get("")
async def get_config(
section: Optional[str] = None,
current_user: dict = Depends(get_current_user),
):
cfg = _get_config()
if section:
if section not in _ALLOWED_SECTIONS and section != "DEFAULT":
raise HTTPException(403, f"不允许访问配置节: {section}")
items = {}
for key, value in cfg.config.items(section):
items[key] = _mask_value(key, value)
return {"section": section, "items": items}
result = {}
for sec in _ALLOWED_SECTIONS:
try:
items = {}
for key, value in cfg.config.items(sec):
items[key] = _mask_value(key, value)
result[sec] = items
except Exception:
pass
return result
@router.put("")
async def update_config(
body: ConfigUpdate,
current_user: dict = Depends(get_current_user),
):
if body.section not in _ALLOWED_SECTIONS:
raise HTTPException(403, f"不允许修改配置节: {body.section}")
cfg = _get_config()
try:
cfg.update(body.section, body.key, body.value)
cfg.save_config()
return {"message": f"已更新 [{body.section}] {body.key}"}
except Exception as e:
raise HTTPException(500, f"保存失败: {e}")
@router.put("/bulk")
async def bulk_update_config(
body: ConfigBulkUpdate,
current_user: dict = Depends(get_current_user),
):
cfg = _get_config()
updated = []
for item in body.updates:
if item.section not in _ALLOWED_SECTIONS:
continue
cfg.update(item.section, item.key, item.value)
updated.append(f"[{item.section}] {item.key}")
cfg.save_config()
return {"message": f"已更新 {len(updated)}", "updated": updated}