mirror of
https://github.com/fastapi-users/fastapi-users.git
synced 2025-08-15 19:30:47 +08:00
Remove list endpoint and related methods
This commit is contained in:
@ -201,26 +201,6 @@ Update the current authenticated active user.
|
|||||||
|
|
||||||
## Superuser
|
## Superuser
|
||||||
|
|
||||||
### `GET /`
|
|
||||||
|
|
||||||
Return the list of registered users.
|
|
||||||
|
|
||||||
!!! success "`200 OK`"
|
|
||||||
```json
|
|
||||||
[{
|
|
||||||
"id": "57cbb51a-ab71-4009-8802-3f54b4f2e23",
|
|
||||||
"email": "king.arthur@camelot.bt",
|
|
||||||
"is_active": true,
|
|
||||||
"is_superuser": false
|
|
||||||
}]
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! fail "`401 Unauthorized`"
|
|
||||||
Missing token or inactive user.
|
|
||||||
|
|
||||||
!!! fail "`403 Forbidden`"
|
|
||||||
Not a superuser.
|
|
||||||
|
|
||||||
### `GET /{user_id}`
|
### `GET /{user_id}`
|
||||||
|
|
||||||
Return the user with id `user_id`.
|
Return the user with id `user_id`.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from typing import Generic, List, Optional, Type
|
from typing import Generic, Optional, Type
|
||||||
|
|
||||||
from fastapi.security import OAuth2PasswordRequestForm
|
from fastapi.security import OAuth2PasswordRequestForm
|
||||||
|
|
||||||
@ -18,10 +18,6 @@ class BaseUserDatabase(Generic[UD]):
|
|||||||
def __init__(self, user_db_model: Type[UD]):
|
def __init__(self, user_db_model: Type[UD]):
|
||||||
self.user_db_model = user_db_model
|
self.user_db_model = user_db_model
|
||||||
|
|
||||||
async def list(self) -> List[UD]:
|
|
||||||
"""List all users."""
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
async def get(self, id: str) -> Optional[UD]:
|
async def get(self, id: str) -> Optional[UD]:
|
||||||
"""Get a single user by id."""
|
"""Get a single user by id."""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from typing import List, Optional, Type
|
from typing import Optional, Type
|
||||||
|
|
||||||
from motor.motor_asyncio import AsyncIOMotorCollection
|
from motor.motor_asyncio import AsyncIOMotorCollection
|
||||||
|
|
||||||
@ -22,9 +22,6 @@ class MongoDBUserDatabase(BaseUserDatabase[UD]):
|
|||||||
self.collection.create_index("id", unique=True)
|
self.collection.create_index("id", unique=True)
|
||||||
self.collection.create_index("email", unique=True)
|
self.collection.create_index("email", unique=True)
|
||||||
|
|
||||||
async def list(self) -> List[UD]:
|
|
||||||
return [self.user_db_model(**user) async for user in self.collection.find()]
|
|
||||||
|
|
||||||
async def get(self, id: str) -> Optional[UD]:
|
async def get(self, id: str) -> Optional[UD]:
|
||||||
user = await self.collection.find_one({"id": id})
|
user = await self.collection.find_one({"id": id})
|
||||||
return self.user_db_model(**user) if user else None
|
return self.user_db_model(**user) if user else None
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from typing import List, Mapping, Optional, Type
|
from typing import Mapping, Optional, Type
|
||||||
|
|
||||||
from databases import Database
|
from databases import Database
|
||||||
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String, Table, select
|
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String, Table, select
|
||||||
@ -75,11 +75,6 @@ class SQLAlchemyUserDatabase(BaseUserDatabase[UD]):
|
|||||||
self.users = users
|
self.users = users
|
||||||
self.oauth_accounts = oauth_accounts
|
self.oauth_accounts = oauth_accounts
|
||||||
|
|
||||||
async def list(self) -> List[UD]:
|
|
||||||
query = self.users.select()
|
|
||||||
users = await self.database.fetch_all(query)
|
|
||||||
return [await self._make_user(user) for user in users]
|
|
||||||
|
|
||||||
async def get(self, id: str) -> Optional[UD]:
|
async def get(self, id: str) -> Optional[UD]:
|
||||||
query = self.users.select().where(self.users.c.id == id)
|
query = self.users.select().where(self.users.c.id == id)
|
||||||
user = await self.database.fetch_one(query)
|
user = await self.database.fetch_one(query)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from typing import List, Optional, Type
|
from typing import Optional, Type
|
||||||
|
|
||||||
from tortoise import fields, models
|
from tortoise import fields, models
|
||||||
from tortoise.exceptions import DoesNotExist
|
from tortoise.exceptions import DoesNotExist
|
||||||
@ -61,16 +61,6 @@ class TortoiseUserDatabase(BaseUserDatabase[UD]):
|
|||||||
self.model = model
|
self.model = model
|
||||||
self.oauth_account_model = oauth_account_model
|
self.oauth_account_model = oauth_account_model
|
||||||
|
|
||||||
async def list(self) -> List[UD]:
|
|
||||||
query = self.model.all()
|
|
||||||
|
|
||||||
if self.oauth_account_model is not None:
|
|
||||||
query = query.prefetch_related("oauth_accounts")
|
|
||||||
|
|
||||||
users = await query
|
|
||||||
|
|
||||||
return [self.user_db_model(**await user.to_dict()) for user in users]
|
|
||||||
|
|
||||||
async def get(self, id: str) -> Optional[UD]:
|
async def get(self, id: str) -> Optional[UD]:
|
||||||
try:
|
try:
|
||||||
query = self.model.get(id=id)
|
query = self.model.get(id=id)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from typing import Any, Dict, List, Type, cast
|
from typing import Any, Dict, Type, cast
|
||||||
|
|
||||||
import jwt
|
import jwt
|
||||||
from fastapi import Body, Depends, HTTPException
|
from fastapi import Body, Depends, HTTPException
|
||||||
@ -185,14 +185,6 @@ def get_user_router(
|
|||||||
|
|
||||||
return updated_user
|
return updated_user
|
||||||
|
|
||||||
@router.get(
|
|
||||||
"/",
|
|
||||||
response_model=List[user_model], # type: ignore
|
|
||||||
dependencies=[Depends(get_current_superuser)],
|
|
||||||
)
|
|
||||||
async def list_users():
|
|
||||||
return await user_db.list()
|
|
||||||
|
|
||||||
@router.get(
|
@router.get(
|
||||||
"/{id}",
|
"/{id}",
|
||||||
response_model=user_model,
|
response_model=user_model,
|
||||||
|
@ -155,9 +155,6 @@ def oauth_account3() -> BaseOAuthAccount:
|
|||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_user_db(user, inactive_user, superuser) -> BaseUserDatabase:
|
def mock_user_db(user, inactive_user, superuser) -> BaseUserDatabase:
|
||||||
class MockUserDatabase(BaseUserDatabase[UserDB]):
|
class MockUserDatabase(BaseUserDatabase[UserDB]):
|
||||||
async def list(self) -> List[UserDB]:
|
|
||||||
return [user, inactive_user, superuser]
|
|
||||||
|
|
||||||
async def get(self, id: str) -> Optional[UserDB]:
|
async def get(self, id: str) -> Optional[UserDB]:
|
||||||
if id == user.id:
|
if id == user.id:
|
||||||
return user
|
return user
|
||||||
@ -193,9 +190,6 @@ def mock_user_db_oauth(
|
|||||||
user_oauth, inactive_user_oauth, superuser_oauth
|
user_oauth, inactive_user_oauth, superuser_oauth
|
||||||
) -> BaseUserDatabase:
|
) -> BaseUserDatabase:
|
||||||
class MockUserDatabase(BaseUserDatabase[UserDBOAuth]):
|
class MockUserDatabase(BaseUserDatabase[UserDBOAuth]):
|
||||||
async def list(self) -> List[UserDBOAuth]:
|
|
||||||
return [user_oauth, inactive_user_oauth, superuser_oauth]
|
|
||||||
|
|
||||||
async def get(self, id: str) -> Optional[UserDBOAuth]:
|
async def get(self, id: str) -> Optional[UserDBOAuth]:
|
||||||
if id == user_oauth.id:
|
if id == user_oauth.id:
|
||||||
return user_oauth
|
return user_oauth
|
||||||
|
@ -18,9 +18,6 @@ def create_oauth2_password_request_form():
|
|||||||
async def test_not_implemented_methods(user):
|
async def test_not_implemented_methods(user):
|
||||||
base_user_db = BaseUserDatabase(UserDB)
|
base_user_db = BaseUserDatabase(UserDB)
|
||||||
|
|
||||||
with pytest.raises(NotImplementedError):
|
|
||||||
await base_user_db.list()
|
|
||||||
|
|
||||||
with pytest.raises(NotImplementedError):
|
with pytest.raises(NotImplementedError):
|
||||||
await base_user_db.get("aaa")
|
await base_user_db.get("aaa")
|
||||||
|
|
||||||
|
@ -77,12 +77,6 @@ async def test_queries(mongodb_user_db: MongoDBUserDatabase[UserDB]):
|
|||||||
assert email_user is not None
|
assert email_user is not None
|
||||||
assert email_user.id == user_db.id
|
assert email_user.id == user_db.id
|
||||||
|
|
||||||
# List
|
|
||||||
users = await mongodb_user_db.list()
|
|
||||||
assert len(users) == 1
|
|
||||||
first_user = users[0]
|
|
||||||
assert first_user.id == user_db.id
|
|
||||||
|
|
||||||
# Exception when inserting existing email
|
# Exception when inserting existing email
|
||||||
with pytest.raises(pymongo.errors.DuplicateKeyError):
|
with pytest.raises(pymongo.errors.DuplicateKeyError):
|
||||||
await mongodb_user_db.create(user)
|
await mongodb_user_db.create(user)
|
||||||
@ -151,13 +145,6 @@ async def test_queries_oauth(
|
|||||||
assert email_user.id == user_db.id
|
assert email_user.id == user_db.id
|
||||||
assert len(email_user.oauth_accounts) == 2
|
assert len(email_user.oauth_accounts) == 2
|
||||||
|
|
||||||
# List
|
|
||||||
users = await mongodb_user_db_oauth.list()
|
|
||||||
assert len(users) == 1
|
|
||||||
first_user = users[0]
|
|
||||||
assert first_user.id == user_db.id
|
|
||||||
assert len(first_user.oauth_accounts) == 2
|
|
||||||
|
|
||||||
# Get by OAuth account
|
# Get by OAuth account
|
||||||
oauth_user = await mongodb_user_db_oauth.get_by_oauth_account(
|
oauth_user = await mongodb_user_db_oauth.get_by_oauth_account(
|
||||||
oauth_account1.oauth_name, oauth_account1.account_id
|
oauth_account1.oauth_name, oauth_account1.account_id
|
||||||
|
@ -97,12 +97,6 @@ async def test_queries(sqlalchemy_user_db: SQLAlchemyUserDatabase[UserDB]):
|
|||||||
assert email_user is not None
|
assert email_user is not None
|
||||||
assert email_user.id == user_db.id
|
assert email_user.id == user_db.id
|
||||||
|
|
||||||
# List
|
|
||||||
users = await sqlalchemy_user_db.list()
|
|
||||||
assert len(users) == 1
|
|
||||||
first_user = users[0]
|
|
||||||
assert first_user.id == user_db.id
|
|
||||||
|
|
||||||
# Exception when inserting existing email
|
# Exception when inserting existing email
|
||||||
with pytest.raises(sqlite3.IntegrityError):
|
with pytest.raises(sqlite3.IntegrityError):
|
||||||
await sqlalchemy_user_db.create(user)
|
await sqlalchemy_user_db.create(user)
|
||||||
@ -193,13 +187,6 @@ async def test_queries_oauth(
|
|||||||
assert email_user.id == user_db.id
|
assert email_user.id == user_db.id
|
||||||
assert len(email_user.oauth_accounts) == 2
|
assert len(email_user.oauth_accounts) == 2
|
||||||
|
|
||||||
# List
|
|
||||||
users = await sqlalchemy_user_db_oauth.list()
|
|
||||||
assert len(users) == 1
|
|
||||||
first_user = users[0]
|
|
||||||
assert first_user.id == user_db.id
|
|
||||||
assert len(first_user.oauth_accounts) == 2
|
|
||||||
|
|
||||||
# Get by OAuth account
|
# Get by OAuth account
|
||||||
oauth_user = await sqlalchemy_user_db_oauth.get_by_oauth_account(
|
oauth_user = await sqlalchemy_user_db_oauth.get_by_oauth_account(
|
||||||
oauth_account1.oauth_name, oauth_account1.account_id
|
oauth_account1.oauth_name, oauth_account1.account_id
|
||||||
|
@ -82,12 +82,6 @@ async def test_queries(tortoise_user_db: TortoiseUserDatabase[UserDB]):
|
|||||||
assert email_user is not None
|
assert email_user is not None
|
||||||
assert email_user.id == user_db.id
|
assert email_user.id == user_db.id
|
||||||
|
|
||||||
# List
|
|
||||||
users = await tortoise_user_db.list()
|
|
||||||
assert len(users) == 1
|
|
||||||
first_user = users[0]
|
|
||||||
assert first_user.id == user_db.id
|
|
||||||
|
|
||||||
# Exception when inserting existing email
|
# Exception when inserting existing email
|
||||||
with pytest.raises(IntegrityError):
|
with pytest.raises(IntegrityError):
|
||||||
await tortoise_user_db.create(user)
|
await tortoise_user_db.create(user)
|
||||||
@ -161,13 +155,6 @@ async def test_queries_oauth(
|
|||||||
assert email_user.id == user_db.id
|
assert email_user.id == user_db.id
|
||||||
assert len(email_user.oauth_accounts) == 2
|
assert len(email_user.oauth_accounts) == 2
|
||||||
|
|
||||||
# List
|
|
||||||
users = await tortoise_user_db_oauth.list()
|
|
||||||
assert len(users) == 1
|
|
||||||
first_user = users[0]
|
|
||||||
assert first_user.id == user_db.id
|
|
||||||
assert len(first_user.oauth_accounts) == 2
|
|
||||||
|
|
||||||
# Get by OAuth account
|
# Get by OAuth account
|
||||||
oauth_user = await tortoise_user_db_oauth.get_by_oauth_account(
|
oauth_user = await tortoise_user_db_oauth.get_by_oauth_account(
|
||||||
oauth_account1.oauth_name, oauth_account1.account_id
|
oauth_account1.oauth_name, oauth_account1.account_id
|
||||||
|
@ -93,9 +93,6 @@ class TestRouter:
|
|||||||
response = await test_app_client.post("/users/reset-password")
|
response = await test_app_client.post("/users/reset-password")
|
||||||
assert response.status_code != status.HTTP_404_NOT_FOUND
|
assert response.status_code != status.HTTP_404_NOT_FOUND
|
||||||
|
|
||||||
response = await test_app_client.get("/users")
|
|
||||||
assert response.status_code != status.HTTP_404_NOT_FOUND
|
|
||||||
|
|
||||||
response = await test_app_client.get("/users/aaa")
|
response = await test_app_client.get("/users/aaa")
|
||||||
assert response.status_code != status.HTTP_404_NOT_FOUND
|
assert response.status_code != status.HTTP_404_NOT_FOUND
|
||||||
|
|
||||||
|
@ -500,34 +500,6 @@ class TestUpdateMe:
|
|||||||
assert isinstance(request, Request)
|
assert isinstance(request, Request)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.router
|
|
||||||
@pytest.mark.asyncio
|
|
||||||
class TestListUsers:
|
|
||||||
async def test_missing_token(self, test_app_client: httpx.AsyncClient):
|
|
||||||
response = await test_app_client.get("/")
|
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
|
||||||
|
|
||||||
async def test_regular_user(self, test_app_client: httpx.AsyncClient, user: UserDB):
|
|
||||||
response = await test_app_client.get(
|
|
||||||
"/", headers={"Authorization": f"Bearer {user.id}"}
|
|
||||||
)
|
|
||||||
assert response.status_code == status.HTTP_403_FORBIDDEN
|
|
||||||
|
|
||||||
async def test_superuser(
|
|
||||||
self, test_app_client: httpx.AsyncClient, superuser: UserDB
|
|
||||||
):
|
|
||||||
response = await test_app_client.get(
|
|
||||||
"/", headers={"Authorization": f"Bearer {superuser.id}"}
|
|
||||||
)
|
|
||||||
assert response.status_code == status.HTTP_200_OK
|
|
||||||
|
|
||||||
response_json = response.json()
|
|
||||||
assert len(response_json) == 3
|
|
||||||
for user in response_json:
|
|
||||||
assert "id" in user
|
|
||||||
assert "hashed_password" not in user
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.router
|
@pytest.mark.router
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
class TestGetUser:
|
class TestGetUser:
|
||||||
|
Reference in New Issue
Block a user