diff --git a/backend/app/routers/admin.py b/backend/app/routers/admin.py index 1d1228d..0b56415 100644 --- a/backend/app/routers/admin.py +++ b/backend/app/routers/admin.py @@ -108,12 +108,34 @@ async def list_users( db: AsyncSession = Depends(get_db), _actor: User = Depends(get_current_user), ): - """Return all users with basic stats.""" - result = await db.execute(sa.select(User).order_by(User.created_at)) - users = result.scalars().all() + """Return all users with basic stats including active session counts.""" + active_sub = ( + sa.select(sa.func.count()) + .select_from(UserSession) + .where( + UserSession.user_id == User.id, + UserSession.revoked == False, + UserSession.expires_at > datetime.now(), + ) + .correlate(User) + .scalar_subquery() + ) + + result = await db.execute( + sa.select(User, active_sub.label("active_sessions")) + .order_by(User.created_at) + ) + rows = result.all() + return UserListResponse( - users=[UserListItem.model_validate(u) for u in users], - total=len(users), + users=[ + UserListItem( + **UserListItem.model_validate(user).model_dump(exclude={"active_sessions"}), + active_sessions=count, + ) + for user, count in rows + ], + total=len(rows), ) diff --git a/backend/app/schemas/admin.py b/backend/app/schemas/admin.py index 7688bc5..e1af013 100644 --- a/backend/app/schemas/admin.py +++ b/backend/app/schemas/admin.py @@ -27,6 +27,7 @@ class UserListItem(BaseModel): totp_enabled: bool mfa_enforce_pending: bool created_at: datetime + active_sessions: int = 0 model_config = ConfigDict(from_attributes=True) @@ -37,7 +38,7 @@ class UserListResponse(BaseModel): class UserDetailResponse(UserListItem): - active_sessions: int + pass # ---------------------------------------------------------------------------