diff --git a/app/exceptions.py b/app/exceptions.py index 984c721..80b8b46 100644 --- a/app/exceptions.py +++ b/app/exceptions.py @@ -92,3 +92,8 @@ class UserAlreadyPinnedChatException(BlackPhoenixException): class UserMustConfirmEmailException(BlackPhoenixException): status_code = status.HTTP_409_CONFLICT detail = "Сначала подтвердите почту" + + +class SomethingWentWrongException(BlackPhoenixException): + status_code = status.HTTP_500_INTERNAL_SERVER_ERROR + detail = "Что-то пошло не так" diff --git a/app/tests/integration_tests/users_api_test.py b/app/tests/integration_tests/users_api_test.py index 28cc105..28c6884 100644 --- a/app/tests/integration_tests/users_api_test.py +++ b/app/tests/integration_tests/users_api_test.py @@ -82,7 +82,7 @@ async def test_rename_user(username: str, password: str, statuscode: int, ac: As }) assert response.status_code == statuscode if response.status_code == 200: - assert response.json() == username + assert response.json()["username"] == username @pytest.mark.parametrize("avatar_url,password,statuscode", [ @@ -105,7 +105,7 @@ async def test_change_avatar(avatar_url: str, password: str, statuscode: int, ac }) assert response.status_code == statuscode if response.status_code == 200: - assert response.json() == avatar_url + assert response.json()["new_avatar_image"] == avatar_url @pytest.mark.parametrize("login_password,current_password,new_password1,new_password2,statuscode", [ diff --git a/app/users/router.py b/app/users/router.py index c42679f..f39f3ad 100644 --- a/app/users/router.py +++ b/app/users/router.py @@ -2,7 +2,8 @@ from fastapi import APIRouter, Response, Depends, status from fastapi.responses import RedirectResponse from app.exceptions import UsernameAlreadyInUseException, \ - IncorrectPasswordException, PasswordsМismatchException, WrongCodeException, UserNotFoundException + IncorrectPasswordException, PasswordsМismatchException, WrongCodeException, UserNotFoundException, \ + SomethingWentWrongException from app.users.auth import get_password_hash, authenticate_user_by_email, \ create_access_token, verify_password, VERIFICATED_USER, authenticate_user, \ check_existing_user, check_verificated_user_with_exc @@ -10,7 +11,8 @@ from app.users.dao import UserDAO, UserCodesDAO from app.users.dependencies import get_current_user from app.users.models import Users from app.users.schemas import SUserLogin, SUserRegister, SUser, SUserPassword, SUserRename, SUserAvatar, \ - SUserPasswordRecover, SUserCode, SUserPasswordChange + SUserPasswordRecover, SUserCode, SUserPasswordChange, SRecoverEmailSent, SUserToken, SEmailVerification, SUserName, \ + SNewAvatar, SConfirmPasswordRecovery, SPasswordRecovered from app.tasks.tasks import send_registration_confirmation_email, send_password_change_email, \ send_password_recover_email @@ -31,7 +33,7 @@ async def get_all_users(): return users -@router.post("/register", response_model=dict[str, str]) +@router.post("/register", response_model=SUserToken) async def register_user(response: Response, user_data: SUserRegister): await check_existing_user(user_data) hashed_password = get_password_hash(user_data.password) @@ -54,17 +56,17 @@ async def register_user(response: Response, user_data: SUserRegister): return {"access_token": access_token} -@router.post('/email_verification', status_code=status.HTTP_200_OK, response_model=bool) +@router.post('/email_verification', status_code=status.HTTP_200_OK, response_model=SEmailVerification) async def email_verification(user_code: SUserCode, user: Users = Depends(get_current_user)): user_codes = await UserCodesDAO.get_user_codes( user_id=user.id, description="Код подтверждения почты", code=user_code.user_code ) if not user_codes or not await UserDAO.change_data(user_id=user.id, role=VERIFICATED_USER): raise WrongCodeException - return True + return {'email_verification': True} -@router.post("/login", response_model=dict[str, str]) +@router.post("/login", response_model=SUserToken) async def login_user(response: Response, user_data: SUserLogin): user = await authenticate_user(user_data.email_or_username, user_data.password) access_token = create_access_token({"sub": str(user.id)}) @@ -82,7 +84,7 @@ async def read_users_me(current_user: Users = Depends(get_current_user)): return current_user -@router.patch("/rename", response_model=str) +@router.patch("/rename", response_model=SUserName) async def rename_user(new_username: SUserRename, current_user: Users = Depends(get_current_user)): await check_verificated_user_with_exc(user_id=current_user.id) if not verify_password(new_username.password, current_user.hashed_password): @@ -91,17 +93,17 @@ async def rename_user(new_username: SUserRename, current_user: Users = Depends(g if existing_user: raise UsernameAlreadyInUseException new_username = await UserDAO.change_data(current_user.id, username=new_username.username) - return new_username + return {'username': new_username} -@router.patch("/change_avatar", response_model=str) +@router.patch("/change_avatar", response_model=SNewAvatar) async def change_avatar(user_data: SUserAvatar, current_user: Users = Depends(get_current_user)): await check_verificated_user_with_exc(user_id=current_user.id) if not verify_password(user_data.password, current_user.hashed_password): raise IncorrectPasswordException if await UserDAO.change_data(current_user.id, avatar_image=user_data.new_avatar_image): - return user_data.new_avatar_image - raise UserNotFoundException + return {'new_avatar_image': user_data.new_avatar_image} + raise SomethingWentWrongException @router.patch("/change_password", status_code=status.HTTP_200_OK) @@ -117,7 +119,7 @@ async def change_password(new_password: SUserPassword, current_user: Users = Dep send_password_change_email.delay(current_user.username, current_user.email) -@router.patch("/send_recovery_email", status_code=status.HTTP_200_OK) +@router.patch("/send_recovery_email", status_code=status.HTTP_200_OK, response_model=SRecoverEmailSent) async def send_recovery_email(email: SUserPasswordRecover): existing_user = await UserDAO.find_one_or_none(email=email.email) if not existing_user: @@ -128,20 +130,21 @@ async def send_recovery_email(email: SUserPasswordRecover): if await UserCodesDAO.set_user_codes( user_id=existing_user.user_id, code=result, description="Код восстановления пароля" ) == result: - return True + return {'recover_email_sent': True} + raise SomethingWentWrongException -@router.post("/confirm_password_recovery", status_code=status.HTTP_200_OK, response_model=int) +@router.post("/confirm_password_recovery", status_code=status.HTTP_200_OK, response_model=SConfirmPasswordRecovery) async def confirm_password_recovery(user_code: SUserCode): user_codes = await UserCodesDAO.get_user_codes( description="Код восстановления пароля", code=user_code.user_code ) if not user_codes: raise WrongCodeException - return user_codes[0]['user_id'] + return {'user_id': user_codes[0]['user_id']} -@router.post("/password_recovery", status_code=status.HTTP_200_OK, response_model=str) +@router.post("/password_recovery", status_code=status.HTTP_200_OK, response_model=SPasswordRecovered) async def password_recovery(passwords: SUserPasswordChange): if passwords.password1 != passwords.password2: raise PasswordsМismatchException @@ -151,4 +154,4 @@ async def password_recovery(passwords: SUserPasswordChange): if not user: raise UserNotFoundException send_password_change_email.delay(user.username, user.email) - return username + return {"username": username} diff --git a/app/users/schemas.py b/app/users/schemas.py index b6068d2..1cf350d 100644 --- a/app/users/schemas.py +++ b/app/users/schemas.py @@ -70,3 +70,31 @@ class SUserPasswordChange(BaseModel): user_id: int password1: str password2: str + + +class SRecoverEmailSent(BaseModel): + recover_email_sent: bool + + +class SEmailVerification(BaseModel): + email_verification: bool + + +class SUserToken(BaseModel): + access_token: str + + +class SUserName(BaseModel): + username: str + + +class SNewAvatar(BaseModel): + new_avatar_image: str + + +class SConfirmPasswordRecovery(BaseModel): + user_id: int + + +class SPasswordRecovered(BaseModel): + username: str