From 0c45cbc17927d5075bf311eecb29afeadaefeaec Mon Sep 17 00:00:00 2001 From: "Brandon H. Goding" Date: Tue, 2 Nov 2021 03:12:43 -0400 Subject: [PATCH] Add a name on every route #762 (#774) * Names for urls added * Tests for Login/Logout Names * Register Name Test * tests/test_router_reset.py * Tests to verify url names in users router * Test Verify Router Names * oauth routes updated with prefix * Test for authorize. Didn't right test for callback as covered under other tests --- fastapi_users/router/auth.py | 4 ++-- fastapi_users/router/oauth.py | 6 +++--- fastapi_users/router/register.py | 2 +- fastapi_users/router/reset.py | 4 ++-- fastapi_users/router/users.py | 6 +++++- fastapi_users/router/verify.py | 4 ++-- tests/test_router_auth.py | 18 ++++++++++++++++++ tests/test_router_oauth.py | 28 ++++++++++++++++++++++++++++ tests/test_router_register.py | 15 +++++++++++++++ tests/test_router_reset.py | 22 ++++++++++++++++++++++ tests/test_router_users.py | 13 +++++++++++++ tests/test_router_verify.py | 26 ++++++++++++++++++++++++++ 12 files changed, 137 insertions(+), 11 deletions(-) diff --git a/fastapi_users/router/auth.py b/fastapi_users/router/auth.py index 5b50f506..6a62c854 100644 --- a/fastapi_users/router/auth.py +++ b/fastapi_users/router/auth.py @@ -19,7 +19,7 @@ def get_auth_router( active=True, verified=requires_verification ) - @router.post("/login") + @router.post("/login", name="auth:login") async def login( response: Response, credentials: OAuth2PasswordRequestForm = Depends(), @@ -41,7 +41,7 @@ def get_auth_router( if backend.logout: - @router.post("/logout") + @router.post("/logout", name="auth:logout") async def logout( response: Response, user=Depends(get_current_user), diff --git a/fastapi_users/router/oauth.py b/fastapi_users/router/oauth.py index ce27bdeb..1bbdbf05 100644 --- a/fastapi_users/router/oauth.py +++ b/fastapi_users/router/oauth.py @@ -30,7 +30,7 @@ def get_oauth_router( ) -> APIRouter: """Generate a router with the OAuth routes.""" router = APIRouter() - callback_route_name = f"{oauth_client.name}-callback" + callback_route_name = f"oauth:{oauth_client.name}-callback" if redirect_url is not None: oauth2_authorize_callback = OAuth2AuthorizeCallback( @@ -43,7 +43,7 @@ def get_oauth_router( route_name=callback_route_name, ) - @router.get("/authorize") + @router.get("/authorize", name="oauth:authorize") async def authorize( request: Request, authentication_backend: str, @@ -74,7 +74,7 @@ def get_oauth_router( return {"authorization_url": authorization_url} - @router.get("/callback", name=f"{oauth_client.name}-callback") + @router.get("/callback", name=f"oauth:{oauth_client.name}-callback") async def callback( request: Request, response: Response, diff --git a/fastapi_users/router/register.py b/fastapi_users/router/register.py index 452262be..4655580b 100644 --- a/fastapi_users/router/register.py +++ b/fastapi_users/router/register.py @@ -21,7 +21,7 @@ def get_register_router( router = APIRouter() @router.post( - "/register", response_model=user_model, status_code=status.HTTP_201_CREATED + "/register", response_model=user_model, status_code=status.HTTP_201_CREATED, name="register:register" ) async def register( request: Request, diff --git a/fastapi_users/router/reset.py b/fastapi_users/router/reset.py index ed7f70e8..e3c38d9d 100644 --- a/fastapi_users/router/reset.py +++ b/fastapi_users/router/reset.py @@ -19,7 +19,7 @@ def get_reset_password_router( """Generate a router with the reset password routes.""" router = APIRouter() - @router.post("/forgot-password", status_code=status.HTTP_202_ACCEPTED) + @router.post("/forgot-password", status_code=status.HTTP_202_ACCEPTED, name="reset:forgot_password") async def forgot_password( request: Request, email: EmailStr = Body(..., embed=True), @@ -37,7 +37,7 @@ def get_reset_password_router( return None - @router.post("/reset-password") + @router.post("/reset-password", name="reset:reset_password") async def reset_password( request: Request, token: str = Body(...), diff --git a/fastapi_users/router/users.py b/fastapi_users/router/users.py index f39e51f3..511fe25e 100644 --- a/fastapi_users/router/users.py +++ b/fastapi_users/router/users.py @@ -42,7 +42,7 @@ def get_users_router( except UserNotExists: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) - @router.get("/me", response_model=user_model) + @router.get("/me", response_model=user_model, name="users:current_user") async def me( user: user_db_model = Depends(get_current_active_user), # type: ignore ): @@ -52,6 +52,7 @@ def get_users_router( "/me", response_model=user_model, dependencies=[Depends(get_current_active_user)], + name="users:current_user" ) async def update_me( request: Request, @@ -81,6 +82,7 @@ def get_users_router( "/{id:uuid}", response_model=user_model, dependencies=[Depends(get_current_superuser)], + name="users:user" ) async def get_user(user=Depends(get_user_or_404)): return user @@ -89,6 +91,7 @@ def get_users_router( "/{id:uuid}", response_model=user_model, dependencies=[Depends(get_current_superuser)], + name="users:user" ) async def update_user( user_update: user_update_model, # type: ignore @@ -119,6 +122,7 @@ def get_users_router( status_code=status.HTTP_204_NO_CONTENT, response_class=Response, dependencies=[Depends(get_current_superuser)], + name="users:user" ) async def delete_user( user=Depends(get_user_or_404), diff --git a/fastapi_users/router/verify.py b/fastapi_users/router/verify.py index b9a039cc..e2107db3 100644 --- a/fastapi_users/router/verify.py +++ b/fastapi_users/router/verify.py @@ -21,7 +21,7 @@ def get_verify_router( ): router = APIRouter() - @router.post("/request-verify-token", status_code=status.HTTP_202_ACCEPTED) + @router.post("/request-verify-token", status_code=status.HTTP_202_ACCEPTED, name="verify:request-token") async def request_verify_token( request: Request, email: EmailStr = Body(..., embed=True), @@ -35,7 +35,7 @@ def get_verify_router( return None - @router.post("/verify", response_model=user_model) + @router.post("/verify", response_model=user_model, name="verify:verify") async def verify( request: Request, token: str = Body(..., embed=True), diff --git a/tests/test_router_auth.py b/tests/test_router_auth.py index 22a8c107..73d39ce5 100644 --- a/tests/test_router_auth.py +++ b/tests/test_router_auth.py @@ -157,6 +157,16 @@ class TestLogin: data = cast(Dict[str, Any], response.json()) assert data["detail"] == ErrorCode.LOGIN_BAD_CREDENTIALS + async def test_login_namespace( + self, + path, + app_factory + ): + split_url = app_factory(True).url_path_for("auth:login").split("/") + assert split_url[len(split_url) - 1] in path + + + @pytest.mark.router @pytest.mark.parametrize("path", ["/mock/logout", "/mock-bis/logout"]) @@ -199,3 +209,11 @@ class TestLogout: path, headers={"Authorization": f"Bearer {verified_user.id}"} ) assert response.status_code == status.HTTP_200_OK + + async def test_logout_namespace( + self, + path, + app_factory + ): + split_url = app_factory(True).url_path_for("auth:logout").split("/") + assert split_url[len(split_url) - 1] in path diff --git a/tests/test_router_oauth.py b/tests/test_router_oauth.py index 6b811a50..53b4e2b1 100644 --- a/tests/test_router_oauth.py +++ b/tests/test_router_oauth.py @@ -272,3 +272,31 @@ class TestCallback: data = cast(Dict[str, Any], response.json()) assert data["token"] == str(user_oauth.id) + + +@pytest.mark.asyncio +async def test_oauth_authorize_namespace( + secret, + get_user_manager_oauth, + mock_authentication, + oauth_client, + get_test_client, + redirect_url: str = None, +): + + mock_authentication_bis = MockAuthentication(name="mock-bis") + authenticator = Authenticator( + [mock_authentication, mock_authentication_bis], get_user_manager_oauth + ) + + app = FastAPI() + app.include_router( + get_oauth_router( + oauth_client, + get_user_manager_oauth, + authenticator, + secret, + redirect_url, + ) + ) + assert app.url_path_for("oauth:authorize") == "/authorize" diff --git a/tests/test_router_register.py b/tests/test_router_register.py index a7f7c909..4bacfc1b 100644 --- a/tests/test_router_register.py +++ b/tests/test_router_register.py @@ -102,3 +102,18 @@ class TestRegister: data = cast(Dict[str, Any], response.json()) assert data["is_active"] is True + + +@pytest.mark.asyncio +async def test_register_namespace( + get_user_manager +): + app = FastAPI() + app.include_router( + get_register_router( + get_user_manager, + User, + UserCreate, + ) + ) + assert app.url_path_for("register:register") == "/register" diff --git a/tests/test_router_reset.py b/tests/test_router_reset.py index e761cb7a..f6d063c1 100644 --- a/tests/test_router_reset.py +++ b/tests/test_router_reset.py @@ -148,3 +148,25 @@ class TestResetPassword: json = {"token": "foo", "password": "guinevere"} response = await test_app_client.post("/reset-password", json=json) assert response.status_code == status.HTTP_200_OK + + +@pytest.mark.asyncio +async def test_forgot_password_namespace( + get_user_manager +): + app = FastAPI() + app.include_router( + get_reset_password_router(get_user_manager) + ) + assert app.url_path_for("reset:forgot_password") == "/forgot-password" + + +@pytest.mark.asyncio +async def test_reset_password_namespace( + get_user_manager +): + app = FastAPI() + app.include_router( + get_reset_password_router(get_user_manager) + ) + assert app.url_path_for("reset:reset_password") == "/reset-password" diff --git a/tests/test_router_users.py b/tests/test_router_users.py index 41d4de0a..14da4b26 100644 --- a/tests/test_router_users.py +++ b/tests/test_router_users.py @@ -98,6 +98,12 @@ class TestMe: assert data["id"] == str(verified_user.id) assert data["email"] == verified_user.email + async def test_current_user_namespace( + self, + app_factory + ): + assert app_factory(True).url_path_for("users:current_user") == "/me" + @pytest.mark.router @pytest.mark.asyncio @@ -465,6 +471,13 @@ class TestGetUser: assert data["id"] == str(user.id) assert "hashed_password" not in data + async def test_get_user_namespace( + self, + app_factory, + user: UserDB + ): + assert app_factory(True).url_path_for("users:user", id=user.id) == f"/{user.id}" + @pytest.mark.router @pytest.mark.asyncio diff --git a/tests/test_router_verify.py b/tests/test_router_verify.py index 9d6594a6..c954a0fd 100644 --- a/tests/test_router_verify.py +++ b/tests/test_router_verify.py @@ -104,6 +104,19 @@ class TestVerifyTokenRequest: response = await test_app_client.post("/request-verify-token", json=json) assert response.status_code == status.HTTP_202_ACCEPTED + async def test_token_namespace( + self, + get_user_manager, + ): + verify_router = get_verify_router( + get_user_manager, + User, + ) + + app = FastAPI() + app.include_router(verify_router) + assert app.url_path_for("verify:request-token") == "/request-verify-token" + @pytest.mark.router @pytest.mark.asyncio @@ -166,3 +179,16 @@ class TestVerify: assert response.status_code == status.HTTP_200_OK data = cast(Dict[str, Any], response.json()) assert data["id"] == str(user.id) + + async def test_verify_namespace( + self, + get_user_manager, + ): + verify_router = get_verify_router( + get_user_manager, + User, + ) + + app = FastAPI() + app.include_router(verify_router) + assert app.url_path_for("verify:verify") == "/verify"