Standardize API response envelopes: use items for collection responses and update tests
This commit is contained in:
@@ -72,12 +72,33 @@ class JailListResponse(CollectionResponse[JailSummary]):
|
||||
pass
|
||||
|
||||
|
||||
class IgnoreListResponse(CollectionResponse[str]):
|
||||
"""Response for ``GET /api/jails/{name}/ignoreip``.
|
||||
|
||||
Returns the jailed ignore list as a standard collection response.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class JailDetailResponse(BaseModel):
|
||||
"""Response for ``GET /api/jails/{name}``."""
|
||||
"""Response for ``GET /api/jails/{name}``.
|
||||
|
||||
Includes the primary jail object together with supplemental metadata
|
||||
required by the UI.
|
||||
"""
|
||||
|
||||
model_config = ConfigDict(strict=True)
|
||||
|
||||
jail: Jail
|
||||
ignore_list: list[str] = Field(
|
||||
default_factory=list,
|
||||
description="List of IP addresses and networks currently ignored by the jail.",
|
||||
)
|
||||
ignore_self: bool = Field(
|
||||
default=False,
|
||||
description="Whether the jail ignores the server's own IP addresses.",
|
||||
)
|
||||
|
||||
|
||||
class JailCommandResponse(CommandResponse):
|
||||
|
||||
@@ -19,6 +19,7 @@ Provides CRUD and control operations for fail2ban jails:
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Body, HTTPException, Path, status
|
||||
@@ -34,6 +35,7 @@ from app.dependencies import (
|
||||
from app.models.ban import JailBannedIpsResponse
|
||||
from app.models.jail import (
|
||||
IgnoreIpRequest,
|
||||
IgnoreListResponse,
|
||||
JailCommandResponse,
|
||||
JailDetailResponse,
|
||||
JailListResponse,
|
||||
@@ -103,7 +105,16 @@ async def get_jail(
|
||||
HTTPException: 404 when the jail does not exist.
|
||||
HTTPException: 502 when fail2ban is unreachable.
|
||||
"""
|
||||
return await jail_service.get_jail(socket_path, name)
|
||||
jail, ignore_list, ignore_self = await asyncio.gather(
|
||||
jail_service.get_jail(socket_path, name),
|
||||
jail_service.get_ignore_list(socket_path, name),
|
||||
jail_service.get_ignore_self(socket_path, name),
|
||||
)
|
||||
return JailDetailResponse(
|
||||
jail=jail,
|
||||
ignore_list=ignore_list,
|
||||
ignore_self=ignore_self,
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -278,14 +289,14 @@ class _IgnoreSelfRequest(IgnoreIpRequest):
|
||||
|
||||
@router.get(
|
||||
"/{name}/ignoreip",
|
||||
response_model=list[str],
|
||||
response_model=IgnoreListResponse,
|
||||
summary="List the ignore IPs for a jail",
|
||||
)
|
||||
async def get_ignore_list(
|
||||
_auth: AuthDep,
|
||||
name: _NamePath,
|
||||
socket_path: Fail2BanSocketDep,
|
||||
) -> list[str]:
|
||||
) -> IgnoreListResponse:
|
||||
"""Return the current ignore list (IP whitelist) for a fail2ban jail.
|
||||
|
||||
Args:
|
||||
@@ -299,7 +310,8 @@ async def get_ignore_list(
|
||||
HTTPException: 404 when the jail does not exist.
|
||||
HTTPException: 502 when fail2ban is unreachable.
|
||||
"""
|
||||
return await jail_service.get_ignore_list(socket_path, name)
|
||||
ignore_list = await jail_service.get_ignore_list(socket_path, name)
|
||||
return IgnoreListResponse(items=ignore_list, total=len(ignore_list))
|
||||
|
||||
|
||||
@router.post(
|
||||
|
||||
@@ -218,7 +218,7 @@ async def list_jail_configs(socket_path: str) -> JailConfigListResponse:
|
||||
)
|
||||
|
||||
if not jail_names:
|
||||
return JailConfigListResponse(jails=[], total=0)
|
||||
return JailConfigListResponse(items=[], total=0)
|
||||
|
||||
responses: list[JailConfigResponse] = await asyncio.gather(
|
||||
*[get_jail_config(socket_path, name) for name in jail_names],
|
||||
@@ -227,7 +227,7 @@ async def list_jail_configs(socket_path: str) -> JailConfigListResponse:
|
||||
|
||||
jails = [r.jail for r in responses]
|
||||
log.info("jail_configs_listed", count=len(jails))
|
||||
return JailConfigListResponse(jails=jails, total=len(jails))
|
||||
return JailConfigListResponse(items=jails, total=len(jails))
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -311,7 +311,7 @@ async def list_inactive_jails(
|
||||
active=len(active_names),
|
||||
inactive=len(inactive),
|
||||
)
|
||||
return InactiveJailListResponse(jails=inactive, total=len(inactive))
|
||||
return InactiveJailListResponse(items=inactive, total=len(inactive))
|
||||
|
||||
|
||||
async def activate_jail(
|
||||
|
||||
Reference in New Issue
Block a user