From 6b3dad85667b124ee45963cc938ed8c352e9c6ef Mon Sep 17 00:00:00 2001 From: urec56 Date: Sat, 30 Mar 2024 15:37:23 +0500 Subject: [PATCH] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B8=D0=BB=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=B4=D1=82=D0=B2=D0=B5=D1=80=D0=B6=D0=B4=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=BF=D0=BE=D1=87=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/tasks/email_templates.py | 4 ++-- app/tasks/tasks.py | 14 +++++++++++++- app/users/dao.py | 2 +- app/users/router.py | 24 +++++++++++++++++------- app/users/schemas.py | 1 + 5 files changed, 34 insertions(+), 11 deletions(-) diff --git a/app/tasks/email_templates.py b/app/tasks/email_templates.py index 8521ba7..94cb494 100644 --- a/app/tasks/email_templates.py +++ b/app/tasks/email_templates.py @@ -8,7 +8,7 @@ from app.config import settings def create_registration_confirmation_template( username: str, email_to: EmailStr, - confirmation_code: str, + confirmation_link: str, ): email = EmailMessage() @@ -19,7 +19,7 @@ def create_registration_confirmation_template( email.set_content( f"""

{username}, лови аптечку

-

{confirmation_code}

+ {confirmation_link} """, subtype="html" ) diff --git a/app/tasks/tasks.py b/app/tasks/tasks.py index a3eb5c6..bf55721 100644 --- a/app/tasks/tasks.py +++ b/app/tasks/tasks.py @@ -1,7 +1,9 @@ +import json import smtplib import random import string +from cryptography.fernet import Fernet from pydantic import EmailStr @@ -19,15 +21,25 @@ def generate_confirmation_code(length=6): @celery.task def send_registration_confirmation_email( + user_id: int, username: str, email_to: EmailStr, MODE: str ): confirmation_code = generate_confirmation_code() + if MODE == 'TEST': return confirmation_code + + load = {"user_id": user_id, "username": username, "email": email_to, "confirmation_code": confirmation_code} + str_load = json.dumps(load) + cipher_suite = Fernet(settings.INVITATION_LINK_TOKEN_KEY) + invitation_token = cipher_suite.encrypt(str_load.encode()) + + confirmation_link = settings.INVITATION_LINK_HOST + '/api/users/email_verification/' + invitation_token.decode() + msg_content = create_registration_confirmation_template( - username=username, email_to=email_to, confirmation_code=confirmation_code + username=username, email_to=email_to, confirmation_link=confirmation_link ) with smtplib.SMTP_SSL(settings.SMTP_HOST, settings.SMTP_PORT) as server: diff --git a/app/users/dao.py b/app/users/dao.py index 63de6e7..7468ebc 100644 --- a/app/users/dao.py +++ b/app/users/dao.py @@ -150,7 +150,7 @@ class UserCodesDAO(BaseDAO): AND now() - usersverificationcodes.date_of_creation < INTERVAL '30 minutes' """ query = (select(UsersVerificationCodes.__table__.columns) - .where((func.now() - UsersVerificationCodes.date_of_creation) < text("INTERVAL '30 minutes'")) + .where((func.now() - UsersVerificationCodes.date_of_creation) < text("INTERVAL '10 minutes'")) .filter_by(**filter_by)) async with async_session_maker() as session: diff --git a/app/users/router.py b/app/users/router.py index 5255579..632a09b 100644 --- a/app/users/router.py +++ b/app/users/router.py @@ -1,3 +1,6 @@ +import json + +from cryptography.fernet import Fernet from fastapi import APIRouter, Response, Depends, status, Request from fastapi.responses import RedirectResponse @@ -50,7 +53,10 @@ async def check_existing_email(email: SEmail): @router.post("/register", response_model=SUserToken, status_code=status.HTTP_201_CREATED) async def register_user(response: Response, user_data: SUserRegister): + if user_data.password != user_data.password2: + raise PasswordsMismatchException await check_existing_user(user_data) + hashed_password = get_password_hash(user_data.password) user_id = await UserDAO.add( email=user_data.email, @@ -60,7 +66,7 @@ async def register_user(response: Response, user_data: SUserRegister): ) result = send_registration_confirmation_email.delay( - username=user_data.username, email_to=user_data.email, MODE=settings.MODE + user_id=user_id, username=user_data.username, email_to=user_data.email, MODE=settings.MODE ) result = result.get() @@ -73,12 +79,16 @@ 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=SEmailVerification) -async def email_verification(user_code: SUserCode, user: Users = Depends(get_current_user)): +@router.get('/email_verification/{user_code}', status_code=status.HTTP_200_OK, response_model=SEmailVerification) +async def email_verification(user_code: str): + invitation_token = user_code.encode() + cipher_suite = Fernet(settings.INVITATION_LINK_TOKEN_KEY) + user_data = cipher_suite.decrypt(invitation_token).decode("utf-8") + user_data = json.loads(user_data) user_codes = await UserCodesDAO.get_user_codes( - user_id=user.id, description="Код подтверждения почты", code=user_code.user_code + user_id=user_data["user_id"], description="Код подтверждения почты", code=user_data["confirmation_code"] ) - if not user_codes or not await UserDAO.change_data(user_id=user.id, role=VERIFICATED_USER): + if not user_codes or not await UserDAO.change_data(user_id=user_data["user_id"], role=VERIFICATED_USER): raise WrongCodeException return {'email_verification': True} @@ -127,12 +137,12 @@ 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)): + if new_password.new_password != new_password.new_password2: + raise PasswordsMismatchException 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.current_password, existing_user.hashed_password): raise IncorrectPasswordException - if new_password.new_password != new_password.new_password2: - raise PasswordsMismatchException hashed_password = get_password_hash(new_password.new_password) await UserDAO.change_data(current_user.id, hashed_password=hashed_password) send_password_change_email.delay(current_user.username, current_user.email, MODE=settings.MODE) diff --git a/app/users/schemas.py b/app/users/schemas.py index 787d018..91d6c10 100644 --- a/app/users/schemas.py +++ b/app/users/schemas.py @@ -15,6 +15,7 @@ class SUserRegister(BaseModel): email: EmailStr username: str = Query(None, min_length=2, max_length=30) password: str = Query(None, min_length=8) + password2: str = Query(None, min_length=8) date_of_birth: date @field_validator("date_of_birth")