from typing import Annotated from fastapi import APIRouter, Response, Depends, UploadFile, File, Body, Form from fastapi.responses import RedirectResponse from starlette import status from app.config import settings from app.exceptions import UserAlreadyExistsException, UsernameAlreadyInUseException, \ IncorrectPasswordException, PasswordsМismatchException, WrongCodeException, UserNotFoundException from app.images.router import upload_file, upload_file_returning_str from app.users.auth import get_password_hash, authenticate_user_by_email, \ create_access_token, verify_password, REGISTRATED_USER, get_user_codes_list, VERIFICATED_USER, authenticate_user, \ check_existing_user 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 from app.tasks.tasks import send_registration_confirmation_email router = APIRouter( prefix="/users", tags=["Пользователи"] ) @router.get("/teleport", response_class=RedirectResponse, status_code=status.HTTP_307_TEMPORARY_REDIRECT) async def get_teleport(): return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ") @router.get("", response_model=list[SUser]) async def get_all_users(): users = await UserDAO.find_all() return users @router.post("/register", response_model=dict[str, str]) async def register_user(response: Response, user_data: SUserRegister): await check_existing_user(user_data) hashed_password = get_password_hash(user_data.password) user_id = await UserDAO.add( email=user_data.email, hashed_password=hashed_password, username=user_data.username, date_of_birth=user_data.date_of_birth, ) result = send_registration_confirmation_email.delay(username=user_data.username, email_to=user_data.email) result = result.get() if await UserCodesDAO.set_user_codes(user_id=user_id, code=result) == 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) return {"access_token": access_token} @router.post('/email_verification', response_model=bool) 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(user_data.email_or_username, user_data.password) access_token = create_access_token({"sub": str(user.id)}) response.set_cookie("black_phoenix_access_token", access_token, httponly=True) return {"access_token": access_token} @router.post("/logout", status_code=status.HTTP_200_OK) async def logout_user(response: Response): response.delete_cookie("black_phoenix_access_token") @router.get("/me", response_model=SUser) async def read_users_me(current_user: Users = Depends(get_current_user)): return current_user @router.patch("/rename", response_model=str) async def rename_user(new_username: SUserRename, current_user: Users = Depends(get_current_user)): 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) if existing_user: raise UsernameAlreadyInUseException new_username = await UserDAO.change_data(current_user.id, username=new_username.username) return new_username @router.patch("/change_avatar", response_model=str) async def change_avatar( new_avatar: Annotated[UploadFile, File()], password: Annotated[SUserAvatar, Body()], current_user: Users = Depends(get_current_user) ): if not verify_password(password.password, current_user.hashed_password): raise IncorrectPasswordException new_avatar_url = await upload_file_returning_str(new_avatar, "upload_avatar") if await UserDAO.change_data(current_user.id, avatar_image=new_avatar_url): return new_avatar_url raise UserNotFoundException # Надо подумать @router.patch("/change_password", status_code=status.HTTP_200_OK) async def change_password(new_password: SUserPassword, current_user: Users = Depends(get_current_user)): existing_user = await UserDAO.find_one_or_none(id=current_user.id) if not verify_password(new_password.password, existing_user.hashed_password): raise IncorrectPasswordException if new_password.new_password != new_password.new_password2: raise PasswordsМismatchException hashed_password = get_password_hash(new_password.new_password) await UserDAO.change_data(current_user.id, hashed_password=hashed_password)