diff --git a/app/exceptions.py b/app/exceptions.py index 405acc9..984c721 100644 --- a/app/exceptions.py +++ b/app/exceptions.py @@ -87,3 +87,8 @@ class UserAlreadyInChatException(BlackPhoenixException): class UserAlreadyPinnedChatException(BlackPhoenixException): status_code = status.HTTP_409_CONFLICT detail = "Юзер уже закрепил чат" + + +class UserMustConfirmEmailException(BlackPhoenixException): + status_code = status.HTTP_409_CONFLICT + detail = "Сначала подтвердите почту" diff --git a/app/tests/conftest.py b/app/tests/conftest.py index fbd0c0e..0e02c77 100644 --- a/app/tests/conftest.py +++ b/app/tests/conftest.py @@ -2,7 +2,7 @@ import json from datetime import datetime import pytest -from sqlalchemy import insert +from sqlalchemy import insert, update from httpx import AsyncClient from app.config import settings @@ -41,12 +41,14 @@ async def prepare_database(): add_chats = insert(Chats).values(chats) add_users_x_chats = insert(UsersXChats).values(users_x_chats) add_messages = insert(Messages).values(messages) + set_verified_user = update(Users).values(role=1).where(Users.id == 3) await session.execute(add_users) await session.execute(add_users_verification_codes) await session.execute(add_chats) await session.execute(add_users_x_chats) await session.execute(add_messages) + await session.execute(set_verified_user) await session.commit() diff --git a/app/tests/integration_tests/users_api_test.py b/app/tests/integration_tests/users_api_test.py index e0d18dc..28cc105 100644 --- a/app/tests/integration_tests/users_api_test.py +++ b/app/tests/integration_tests/users_api_test.py @@ -87,8 +87,12 @@ async def test_rename_user(username: str, password: str, statuscode: int, ac: As @pytest.mark.parametrize("avatar_url,password,statuscode", [ ("https://images.black-phoenix.ru/static/images/avatars/v6BtxTxfCFi2dBAl_avatar.png", "12311231", 200), - ("https://images.black-phoenix.ru/static/images/%D1%82%D1%8B%20%D1%83%D0%B6%D0%B5%20%D0%BF%D0%B5%D1%88%D0%BA%D0%B0%20BP.png", "adw", 409), - ("https://images.black-phoenix.ru/static/images/%D1%82%D1%8B%20%D1%83%D0%B6%D0%B5%20%D0%BF%D0%B5%D1%88%D0%BA%D0%B0%20BP.png", "12311231", 200), + ( + "https://images.black-phoenix.ru/static/images/%D1%82%D1%8B%20%D1%83%D0%B6%D0%B5%20%D0%BF%D0%B5%D1%88%D0%BA%D0%B0%20BP.png", + "adw", 409), + ( + "https://images.black-phoenix.ru/static/images/%D1%82%D1%8B%20%D1%83%D0%B6%D0%B5%20%D0%BF%D0%B5%D1%88%D0%BA%D0%B0%20BP.png", + "12311231", 200), ]) async def test_change_avatar(avatar_url: str, password: str, statuscode: int, ac: AsyncClient): await ac.post("/users/login", json={ @@ -102,3 +106,31 @@ 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 + + +@pytest.mark.parametrize("login_password,current_password,new_password1,new_password2,statuscode", [ + ("12311231", "12311231", "12311231", "12311231", 200), + ("12311231", "12311231", "1231121", "12311231", 422), + ("12311231", "12311231", "1231121", "1231231", 422), + ("12311231", "12311231", "1231121", "1231121", 422), + ("12311231", "12311231", "12311231", "1231121", 422), + ("12311231", "1231131", "12311231", "12311231", 422), + ("12311231", "12311231", "12311241", "12311241", 200), + ("12311241", "12311231", "12311241", "12311241", 409), + ("12311241", "12311241", "12311231", "12311231", 200), +]) +async def test_change_password( + login_password: str, current_password: str, new_password1: str, new_password2: str, statuscode: int, ac: AsyncClient +): + await ac.post("/users/login", json={ + "email_or_username": "urec@urec.com", + "password": login_password + }) + response = await ac.patch("/users/change_password", json={ + "current_password": current_password, + "new_password": new_password1, + "new_password2": new_password2 + }) + + assert response.status_code == statuscode + diff --git a/app/users/auth.py b/app/users/auth.py index 6c01c70..cf2b4bb 100644 --- a/app/users/auth.py +++ b/app/users/auth.py @@ -6,7 +6,7 @@ from pydantic import EmailStr from app.config import settings from app.exceptions import UserDontHavePermissionException, IncorrectAuthDataException, UserAlreadyExistsException, \ - UserNotFoundException + UserNotFoundException, UserMustConfirmEmailException from app.users.dao import UserDAO from app.users.models import Users from app.users.schemas import SUserRegister @@ -81,7 +81,7 @@ async def check_verificated_user(user_id: int) -> bool: async def check_verificated_user_with_exc(user_id: int) -> bool: if not await check_verificated_user(user_id=user_id): - raise UserDontHavePermissionException + raise UserMustConfirmEmailException async def get_user_allowed_chats_id(user_id: int): diff --git a/app/users/router.py b/app/users/router.py index 957d02d..c42679f 100644 --- a/app/users/router.py +++ b/app/users/router.py @@ -5,7 +5,7 @@ from app.exceptions import UsernameAlreadyInUseException, \ IncorrectPasswordException, PasswordsМismatchException, WrongCodeException, UserNotFoundException 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_existing_user, check_verificated_user_with_exc from app.users.dao import UserDAO, UserCodesDAO from app.users.dependencies import get_current_user from app.users.models import Users @@ -50,7 +50,7 @@ async def register_user(response: Response, user_data: SUserRegister): ) == result: user = await authenticate_user_by_email(user_data.email, user_data.password) access_token = create_access_token({"sub": str(user.id)}) - response.set_cookie(key="black_phoenix_access_token", value=access_token, httponly=True) + response.set_cookie(key="black_phoenix_access_token", value=access_token, httponly=True, secure=True) return {"access_token": access_token} @@ -84,6 +84,7 @@ async def read_users_me(current_user: Users = Depends(get_current_user)): @router.patch("/rename", response_model=str) 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): raise IncorrectPasswordException existing_user = await UserDAO.find_one_or_none(username=new_username.username) @@ -95,6 +96,7 @@ async def rename_user(new_username: SUserRename, current_user: Users = Depends(g @router.patch("/change_avatar", response_model=str) 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): @@ -104,8 +106,9 @@ async def change_avatar(user_data: SUserAvatar, current_user: Users = Depends(ge @router.patch("/change_password", status_code=status.HTTP_200_OK) async def change_password(new_password: SUserPassword, current_user: Users = Depends(get_current_user)): + await check_verificated_user_with_exc(user_id=current_user.id) existing_user = await UserDAO.find_one_or_none(id=current_user.id) - if not verify_password(new_password.password, existing_user.hashed_password): + if not verify_password(new_password.current_password, existing_user.hashed_password): raise IncorrectPasswordException if new_password.new_password != new_password.new_password2: raise PasswordsМismatchException diff --git a/app/users/schemas.py b/app/users/schemas.py index 925d9c2..b6068d2 100644 --- a/app/users/schemas.py +++ b/app/users/schemas.py @@ -53,7 +53,7 @@ class SUserAvatar(BaseModel): class SUserPassword(BaseModel): - password: str = Query(None, min_length=8) + current_password: str = Query(None, min_length=8) new_password: str = Query(None, min_length=8) new_password2: str = Query(None, min_length=8)