fix(api): return real total for user pagination

This commit is contained in:
2026-09-15 10:55:29 +08:00
parent 682c26fddd
commit 45e1b4b106
3 changed files with 35 additions and 3 deletions
+4 -1
View File
@@ -7,6 +7,7 @@ from sqlalchemy.engine.url import make_url
from sqlalchemy.exc import IntegrityError, SQLAlchemyError from sqlalchemy.exc import IntegrityError, SQLAlchemyError
from sqlalchemy.ext.asyncio import create_async_engine from sqlalchemy.ext.asyncio import create_async_engine
from app.api.pagination import PaginatedList
from app.auth.metadata_dependencies import ( from app.auth.metadata_dependencies import (
get_current_metadata_admin, get_current_metadata_admin,
get_metadata_repository, get_metadata_repository,
@@ -236,7 +237,9 @@ async def list_metadata_users(
metadata_repo: MetadataRepository = Depends(get_metadata_repository), metadata_repo: MetadataRepository = Depends(get_metadata_repository),
) -> List[MetadataUserResponse]: ) -> List[MetadataUserResponse]:
users = await metadata_repo.list_users(skip=skip, limit=limit) users = await metadata_repo.list_users(skip=skip, limit=limit)
return [MetadataUserResponse.model_validate(user) for user in users] total = await metadata_repo.count_users()
items = [MetadataUserResponse.model_validate(user) for user in users]
return PaginatedList(items, total=total)
@router.get("/admin/projects", response_model=List[AdminProjectResponse]) @router.get("/admin/projects", response_model=List[AdminProjectResponse])
@@ -4,7 +4,7 @@ from typing import Optional, List
from uuid import UUID, uuid4 from uuid import UUID, uuid4
from cryptography.fernet import InvalidToken from cryptography.fernet import InvalidToken
from sqlalchemy import delete, select from sqlalchemy import delete, func, select
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from app.core.encryption import ( from app.core.encryption import (
@@ -122,6 +122,12 @@ class MetadataRepository:
) )
return list(result.scalars().all()) return list(result.scalars().all())
async def count_users(self) -> int:
result = await self.session.execute(
select(func.count()).select_from(models.User)
)
return int(result.scalar() or 0)
async def upsert_user_from_keycloak( async def upsert_user_from_keycloak(
self, self,
*, *,
+24 -1
View File
@@ -7,8 +7,9 @@ import pytest
from fastapi import HTTPException from fastapi import HTTPException
from fastapi import Response from fastapi import Response
from app.auth.metadata_dependencies import get_current_metadata_admin
from app.api.v1.endpoints import admin_metadata from app.api.v1.endpoints import admin_metadata
from app.api.pagination import PaginatedList
from app.auth.metadata_dependencies import get_current_metadata_admin
from app.domain.schemas.admin_metadata import ( from app.domain.schemas.admin_metadata import (
AdminProjectCreateRequest, AdminProjectCreateRequest,
MetadataUsersBatchSyncRequest, MetadataUsersBatchSyncRequest,
@@ -83,6 +84,28 @@ def test_to_async_sqlalchemy_url_preserves_password():
assert "***" not in url assert "***" not in url
@pytest.mark.anyio
async def test_list_metadata_users_returns_page_with_real_total():
users = [_user(username="alice"), _user(username="bob")]
repo = SimpleNamespace(
list_users=AsyncMock(return_value=users),
count_users=AsyncMock(return_value=7),
)
response = await admin_metadata.list_metadata_users(
skip=2,
limit=2,
current_user=_user(role="admin", is_superuser=True),
metadata_repo=repo,
)
assert isinstance(response, PaginatedList)
assert response.total == 7
assert [item.username for item in response] == ["alice", "bob"]
repo.list_users.assert_awaited_once_with(skip=2, limit=2)
repo.count_users.assert_awaited_once_with()
@pytest.mark.anyio @pytest.mark.anyio
async def test_sync_metadata_user_upserts_without_password(monkeypatch): async def test_sync_metadata_user_upserts_without_password(monkeypatch):
keycloak_id = uuid4() keycloak_id = uuid4()