diff --git a/chat_test/app/admin/auth.py b/chat_test/app/admin/auth.py index 4168163..15d23fc 100644 --- a/chat_test/app/admin/auth.py +++ b/chat_test/app/admin/auth.py @@ -2,11 +2,9 @@ from sqladmin.authentication import AuthenticationBackend from starlette.requests import Request from app.config import settings -from app.users.auth import authenticate_user_by_username, create_access_token, validate_user_admin +from app.users.auth import authenticate_user_by_username, create_access_token, validate_user_admin, ADMIN_USER from app.users.dependencies import get_current_user -ADMIN_ROLE = 100 - class AdminAuth(AuthenticationBackend): async def login(self, request: Request) -> bool: @@ -14,7 +12,7 @@ class AdminAuth(AuthenticationBackend): username, password = form["username"], form["password"] user = await authenticate_user_by_username(username, password) - if user and user.role == ADMIN_ROLE: + if user and user.role == ADMIN_USER: access_token = create_access_token({"sub": str(user.id)}) request.session.update({"token": access_token}) diff --git a/chat_test/app/exceptions.py b/chat_test/app/exceptions.py index 9462cfa..59ebe0f 100644 --- a/chat_test/app/exceptions.py +++ b/chat_test/app/exceptions.py @@ -67,3 +67,8 @@ class PasswordsМismatchException(BlackPhoenixException): class UserCanNotReadThisChatException(BlackPhoenixException): status_code = status.HTTP_409_CONFLICT detail = "Юзер не может читать этот чат" + + +class WrongCodeException(BlackPhoenixException): + status_code = status.HTTP_409_CONFLICT + detail = 'Введён не верный код подтверждения' diff --git a/chat_test/app/users/auth.py b/chat_test/app/users/auth.py index cdf221e..843c770 100644 --- a/chat_test/app/users/auth.py +++ b/chat_test/app/users/auth.py @@ -11,7 +11,9 @@ from app.users.models import Users pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") -ADMIN_ROLE = 100 +ADMIN_USER = 100 +REGISTRATED_USER = 0 +VERIFICATED_USER = 1 def get_password_hash(password: str) -> str: @@ -64,6 +66,11 @@ async def validate_user_access_to_chat(user_id: int, chat_id: int): async def validate_user_admin(user_id: int): user_role = await UserDAO.get_user_role(user_id=user_id) - if user_role == ADMIN_ROLE: + if user_role == ADMIN_USER: return True return False + + +def get_user_codes_list(user_codes: list[dict], sort_description: str) -> list[str]: + user_codes_list = [user_code['code'] for user_code in user_codes if user_code['description'] == sort_description] + return user_codes_list diff --git a/chat_test/app/users/dao.py b/chat_test/app/users/dao.py index 7911bd6..aa06afe 100644 --- a/chat_test/app/users/dao.py +++ b/chat_test/app/users/dao.py @@ -1,5 +1,8 @@ -from sqlalchemy import update, select, insert +from datetime import datetime + +from sqlalchemy import update, select, insert, and_, func, literal, text from sqlalchemy.exc import SQLAlchemyError +from sqlalchemy.dialects.postgresql import INTERVAL from app.dao.base import BaseDAO from app.database import async_session_maker, engine @@ -96,5 +99,26 @@ class UserCodesDAO(BaseDAO): return result.scalar() @classmethod - async def get_user_codes(cls, user_id: int): - pass + async def get_user_codes(cls, user_id: int) -> list[dict[str, str | int | datetime]]: + """ + SELECT + usersverificationcodes.id, + usersverificationcodes.user_id, + usersverificationcodes.code, + usersverificationcodes.description, + usersverificationcodes.date_of_creation + FROM usersverificationcodes + WHERE + usersverificationcodes.user_id = 20 + AND now() - usersverificationcodes.date_of_creation < INTERVAL '30 minutes' + """ + query = select(UsersVerificationCodes.__table__.columns).where( + and_( + UsersVerificationCodes.user_id == user_id, + (func.now() - UsersVerificationCodes.date_of_creation) < text("INTERVAL '30 minutes'") + )) + async with async_session_maker() as session: + # print(query.compile(engine, compile_kwargs={"literal_binds": True})) # Проверка SQL запроса + result = await session.execute(query) + result = result.mappings().all() + return result diff --git a/chat_test/app/users/router.py b/chat_test/app/users/router.py index 31c4be3..a2646a6 100644 --- a/chat_test/app/users/router.py +++ b/chat_test/app/users/router.py @@ -3,9 +3,9 @@ from fastapi.responses import RedirectResponse from starlette import status from app.exceptions import UserAlreadyExistsException, IncorrectAuthDataException, UsernameAlreadyInUseException, \ - IncorrectPasswordException, PasswordsМismatchException + IncorrectPasswordException, PasswordsМismatchException, WrongCodeException from app.users.auth import get_password_hash, authenticate_user_by_email, authenticate_user_by_username, \ - create_access_token, verify_password + create_access_token, verify_password, REGISTRATED_USER, get_user_codes_list, VERIFICATED_USER from app.users.dao import UserDAO, UserCodesDAO from app.users.dependencies import get_current_user from app.users.models import Users @@ -43,7 +43,7 @@ async def register_user(response: Response, user_data: SUserRegister): hashed_password=hashed_password, username=user_data.username, date_of_birth=user_data.date_of_birth, - role=0, + role=REGISTRATED_USER, black_phoenix=False ) @@ -57,6 +57,16 @@ async def register_user(response: Response, user_data: SUserRegister): return {"access_token": access_token} +@router.post('/email_verification') +async def email_verification(user_code: str, user: Users = Depends(get_current_user)): + user_codes = await UserCodesDAO.get_user_codes(user_id=user.id) + user_codes = get_user_codes_list(user_codes=user_codes, sort_description="Код подтверждения почты") + if user_code in user_codes: + if await UserDAO.change_data(user_id=user.id, role=VERIFICATED_USER): + return True + raise WrongCodeException + + @router.post("/login", response_model=dict[str, str]) async def login_user(response: Response, user_data: SUserLogin): user = await authenticate_user_by_email(user_data.email_or_username, user_data.password)