This commit is contained in:
@@ -11,7 +11,7 @@ This router hides that fan-out behind mac_address + group + status.
|
||||
"""
|
||||
from fastapi import APIRouter, Depends
|
||||
from pydantic import ValidationError
|
||||
from sqlalchemy import delete, func, select, update
|
||||
from sqlalchemy import delete, func, or_, select, update
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
@@ -55,8 +55,18 @@ def _stage_client(db: Session, cli: ClientCreate) -> None:
|
||||
|
||||
|
||||
@router.get("/", response_model=Page[ClientOut])
|
||||
def list_clients(page: PageParams = Depends(), db: Session = Depends(get_db)):
|
||||
"""List clients — MAC, group and status, joined from customers + radusergroup."""
|
||||
def list_clients(
|
||||
page: PageParams = Depends(),
|
||||
search: str | None = None,
|
||||
status: str | None = None,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""List clients — MAC, group and status, joined from customers + radusergroup.
|
||||
|
||||
Optional filters:
|
||||
- ``search`` case-insensitive substring match across MAC, name, phone, alias.
|
||||
- ``status`` exact match on billing status (new/paid/unpaid).
|
||||
"""
|
||||
base = (
|
||||
select(
|
||||
Customer.mac_address, RadUserGroup.groupname, Customer.status,
|
||||
@@ -65,7 +75,28 @@ def list_clients(page: PageParams = Depends(), db: Session = Depends(get_db)):
|
||||
.outerjoin(RadUserGroup, RadUserGroup.username == Customer.username)
|
||||
.outerjoin(RadadminClient, RadadminClient.mac_address == Customer.username)
|
||||
)
|
||||
total = db.execute(select(func.count()).select_from(Customer)).scalar_one()
|
||||
# Count over the same joins so filtered totals drive pagination correctly.
|
||||
count_stmt = (
|
||||
select(func.count())
|
||||
.select_from(Customer)
|
||||
.outerjoin(RadadminClient, RadadminClient.mac_address == Customer.username)
|
||||
)
|
||||
|
||||
if search:
|
||||
term = f"%{search.strip()}%"
|
||||
cond = or_(
|
||||
Customer.mac_address.ilike(term),
|
||||
RadadminClient.name.ilike(term),
|
||||
RadadminClient.phone.ilike(term),
|
||||
RadadminClient.alias.ilike(term),
|
||||
)
|
||||
base = base.where(cond)
|
||||
count_stmt = count_stmt.where(cond)
|
||||
if status:
|
||||
base = base.where(Customer.status == status)
|
||||
count_stmt = count_stmt.where(Customer.status == status)
|
||||
|
||||
total = db.execute(count_stmt).scalar_one()
|
||||
rows = db.execute(base.order_by(Customer.id.desc()).limit(page.limit).offset(page.offset)).all()
|
||||
items = [
|
||||
ClientOut(mac_address=mac, group=gn, status=st, name=nm, phone=ph, alias=al)
|
||||
|
||||
Reference in New Issue
Block a user