feat: add admin config diagnostics

This commit is contained in:
Lan
2026-06-03 08:01:55 +08:00
parent e75fe596d0
commit 2d18b02005
2 changed files with 179 additions and 3 deletions
+163 -2
View File
@@ -1649,8 +1649,169 @@ class ConfigService:
}
FLOAT_FIELDS = {"opacity"}
def get_config(self):
return dict(settings.items())
def get_config(self, include_diagnostics: bool = True):
config = dict(settings.items())
if not include_diagnostics:
return config
diagnostics = self.build_config_diagnostics(config)
return {
**config,
"diagnostics": diagnostics,
"diagnosticItems": diagnostics["items"],
"diagnostic_items": diagnostics["items"],
"diagnosticSummary": diagnostics["summary"],
"diagnostic_summary": diagnostics["summary"],
}
def build_config_diagnostics(self, config: Optional[dict[str, Any]] = None) -> dict[str, Any]:
config = config or dict(settings.items())
items: list[dict[str, Any]] = []
def add_item(
key: str,
severity: str,
category: str,
field: Optional[str],
priority: int,
count: int = 1,
fields: Optional[list[str]] = None,
) -> None:
target_fields = fields or ([field] if field else [])
action = {
"type": "field" if field else "section",
"field": field,
"fields": target_fields,
"category": category,
}
items.append(
{
"key": key,
"severity": severity,
"category": category,
"priority": priority,
"count": max(int(count or 0), 0),
"field": field,
"fields": target_fields,
"action": action,
"actionType": action["type"],
"action_type": action["type"],
"targetField": field,
"target_field": field,
}
)
admin_token = str(config.get("admin_token") or "")
if admin_token == settings.default_config.get("admin_token"):
add_item("default_admin_password", "danger", "security", "admin_token", 100)
file_storage = str(config.get("file_storage") or "local").strip().lower()
if file_storage == "s3":
missing_fields = [
field
for field in ["s3_access_key_id", "s3_secret_access_key", "s3_bucket_name"]
if not str(config.get(field) or "").strip()
]
if missing_fields:
add_item(
"s3_incomplete",
"danger",
"storage",
missing_fields[0],
95,
count=len(missing_fields),
fields=missing_fields,
)
elif file_storage == "webdav":
missing_fields = [
field
for field in ["webdav_url", "webdav_username", "webdav_password"]
if not str(config.get(field) or "").strip()
]
if missing_fields:
add_item(
"webdav_incomplete",
"danger",
"storage",
missing_fields[0],
95,
count=len(missing_fields),
fields=missing_fields,
)
if self._to_int(config.get("openUpload")) and self._to_int(config.get("max_save_seconds")) <= 0:
add_item("guest_upload_retention", "warning", "retention", "max_save_seconds", 80)
if (
self._to_int(config.get("uploadSize")) >= 50 * 1024 * 1024
and not self._to_int(config.get("enableChunk"))
):
add_item("chunking_recommended", "warning", "upload", "enableChunk", 70)
if self._to_int(config.get("uploadMinute")) <= 0 or self._to_int(config.get("uploadCount")) <= 0:
add_item(
"upload_guard_disabled",
"warning",
"upload",
"uploadMinute",
60,
fields=["uploadMinute", "uploadCount"],
)
if self._to_int(config.get("errorMinute")) <= 0 or self._to_int(config.get("errorCount")) <= 0:
add_item(
"access_guard_disabled",
"warning",
"security",
"errorMinute",
55,
fields=["errorMinute", "errorCount"],
)
expire_style = config.get("expireStyle")
if not isinstance(expire_style, list) or len(expire_style) == 0:
add_item("expiration_style_empty", "danger", "retention", "expireStyle", 75)
if not items:
add_item("healthy", "success", "system", None, 10, count=0)
items.sort(key=lambda item: (-item["priority"], item["key"]))
summary = self._build_config_diagnostic_summary(items)
return {
"items": items,
"diagnosticItems": items,
"diagnostic_items": items,
"summary": summary,
"diagnosticSummary": summary,
"diagnostic_summary": summary,
}
def _build_config_diagnostic_summary(self, items: list[dict[str, Any]]) -> dict[str, Any]:
severity_order = {"danger": 3, "warning": 2, "neutral": 1, "success": 0}
strongest_severity = max(
(item["severity"] for item in items),
key=lambda severity: severity_order.get(severity, 0),
default="success",
)
return {
"total": len(items),
"dangerCount": sum(1 for item in items if item["severity"] == "danger"),
"danger_count": sum(1 for item in items if item["severity"] == "danger"),
"warningCount": sum(1 for item in items if item["severity"] == "warning"),
"warning_count": sum(1 for item in items if item["severity"] == "warning"),
"successCount": sum(1 for item in items if item["severity"] == "success"),
"success_count": sum(1 for item in items if item["severity"] == "success"),
"neutralCount": sum(1 for item in items if item["severity"] == "neutral"),
"neutral_count": sum(1 for item in items if item["severity"] == "neutral"),
"strongestSeverity": strongest_severity,
"strongest_severity": strongest_severity,
}
def _to_int(self, value: Any) -> int:
try:
return int(value or 0)
except (TypeError, ValueError):
return 0
async def update_config(self, data: dict):
current_config = dict(settings.items())
+16 -1
View File
@@ -494,13 +494,28 @@ async def get_config(
return APIResponse(detail=config_service.get_config())
@admin_api.get("/config/diagnostics")
async def get_config_diagnostics(
config_service: ConfigService = Depends(get_config_service),
):
return APIResponse(detail=config_service.build_config_diagnostics())
@admin_api.patch("/config/update")
async def update_config(
data: dict,
config_service: ConfigService = Depends(get_config_service),
file_service: FileService = Depends(get_file_service),
):
data.pop("themesChoices", None)
for field in (
"themesChoices",
"diagnostics",
"diagnosticItems",
"diagnostic_items",
"diagnosticSummary",
"diagnostic_summary",
):
data.pop(field, None)
await config_service.update_config(data)
await file_service.record_admin_activity(
action="config.update",