Files
apcupsd-client/app/routes/api_config.py
T
Ketan Patel 94f7ed8411
Build and Deploy / build-and-deploy (push) Successful in 25s
Show energy cost on dashboard
2026-06-20 10:49:06 -04:00

152 lines
4.8 KiB
Python

"""Configuration CRUD endpoints (UPS, SMTP, UI). All require session+CSRF for writes."""
from fastapi import APIRouter, Depends, HTTPException, Request
from pydantic import ValidationError
from ..auth import require_session, require_session_and_csrf
from ..config import SMTPConfig, UIConfig, UPSConfig
from ..config_manager import (
ConfigWriteError,
UPSConfigUpdate,
config_manager,
smtp_redacted_dict,
)
from ..notifications.email import EmailSendError, send_test_email
from ..rate_limit import limiter
router = APIRouter(prefix="/api/config")
@router.get("/ups")
async def get_ups_configs(user=Depends(require_session)):
try:
ups_list = await config_manager.get_ups_list()
return [ups.model_dump() for ups in ups_list]
except Exception as e: # noqa: BLE001
raise HTTPException(status_code=500, detail=str(e))
@router.get("/ups/{ups_name}")
async def get_ups_config(ups_name: str, user=Depends(require_session)):
ups = await config_manager.get_ups(ups_name)
if not ups:
raise HTTPException(status_code=404, detail="UPS not found")
return ups.model_dump()
@router.post("/ups")
@limiter.limit("30/minute")
async def add_ups_config(
request: Request, ups_config: UPSConfig, user=Depends(require_session_and_csrf)
):
try:
await config_manager.add_ups(ups_config)
return {"message": "UPS configuration added successfully"}
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
except ConfigWriteError as e:
raise HTTPException(status_code=507, detail=str(e))
@router.put("/ups/{ups_name}")
@limiter.limit("30/minute")
async def update_ups_config(
request: Request,
ups_name: str,
updates: UPSConfigUpdate,
user=Depends(require_session_and_csrf),
):
try:
success = await config_manager.update_ups(ups_name, updates)
if not success:
raise HTTPException(status_code=404, detail="UPS not found")
return {"message": "UPS configuration updated successfully"}
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
except ConfigWriteError as e:
raise HTTPException(status_code=507, detail=str(e))
@router.delete("/ups/{ups_name}")
@limiter.limit("30/minute")
async def delete_ups_config(
request: Request, ups_name: str, user=Depends(require_session_and_csrf)
):
success = await config_manager.delete_ups(ups_name)
if not success:
raise HTTPException(status_code=404, detail="UPS not found")
return {"message": "UPS configuration deleted successfully"}
@router.post("/ups/{ups_name}/test")
@limiter.limit("5/minute")
async def test_ups_connection(
request: Request, ups_name: str, user=Depends(require_session_and_csrf)
):
ups = await config_manager.get_ups(ups_name)
if not ups:
raise HTTPException(status_code=404, detail="UPS not found")
return await config_manager.validate_ups_connection(ups)
@router.post("/ups/test")
@limiter.limit("5/minute")
async def test_new_ups_connection(
request: Request, ups_config: UPSConfig, user=Depends(require_session_and_csrf)
):
return await config_manager.validate_ups_connection(ups_config)
@router.get("/smtp")
async def get_smtp_config(user=Depends(require_session)):
smtp = await config_manager.get_smtp_config()
return smtp_redacted_dict(smtp)
@router.put("/smtp")
@limiter.limit("30/minute")
async def update_smtp_config(
request: Request, smtp_config: SMTPConfig, user=Depends(require_session_and_csrf)
):
await config_manager.update_smtp_config(smtp_config)
return {"message": "SMTP configuration updated"}
@router.post("/smtp/test")
@limiter.limit("5/minute")
async def test_smtp(request: Request, user=Depends(require_session_and_csrf)):
smtp = await config_manager.get_smtp_config()
if not smtp:
raise HTTPException(status_code=400, detail="SMTP not configured")
try:
send_test_email(smtp)
except EmailSendError as e:
raise HTTPException(status_code=502, detail=str(e))
return {"message": "Test email sent"}
@router.get("/ui")
async def get_ui_config(user=Depends(require_session)):
from ..config import load_config
cfg = load_config()
return cfg.ui.model_dump()
@router.put("/ui")
@limiter.limit("30/minute")
async def update_ui_config(
request: Request, payload: dict, user=Depends(require_session_and_csrf)
):
from ..config import load_config
cfg = load_config()
ui_dict = cfg.ui.model_dump()
for k, v in payload.items():
if k in ui_dict:
ui_dict[k] = v
try:
new_ui = UIConfig(**ui_dict)
except ValidationError as e:
raise HTTPException(status_code=422, detail=e.errors())
await config_manager.update_ui_config(new_ui)
return {"message": "UI config updated", "ui": new_ui.model_dump()}