From 5d18f873e9b72bd00d69e42a10c566d44a0c5255 Mon Sep 17 00:00:00 2001 From: l3wdfut4pwr Date: Mon, 27 Apr 2026 22:42:54 +0300 Subject: add password change --- app/routes/users/security.py | 0 app/routes/users/user.py | 55 ++++++++++++++++++++++++++++++++++++++++++-- app/schemas/user.py | 11 +++++++++ 3 files changed, 64 insertions(+), 2 deletions(-) delete mode 100644 app/routes/users/security.py (limited to 'app') diff --git a/app/routes/users/security.py b/app/routes/users/security.py deleted file mode 100644 index e69de29..0000000 diff --git a/app/routes/users/user.py b/app/routes/users/user.py index 8b0b4f5..ed0e898 100644 --- a/app/routes/users/user.py +++ b/app/routes/users/user.py @@ -1,11 +1,12 @@ -from fastapi import APIRouter, Depends, HTTPException +from fastapi import APIRouter, Body, Depends, HTTPException from sqlalchemy.ext.asyncio import AsyncSession from app.auth.dependencies import get_current_user from app.models.user import User from app.schemas.profile import DescriptionUpdate -from app.schemas.user import UserRead +from app.schemas.user import ChangeEmail, ChangePassword, UserRead from app.utils.db import get_async_session +from app.utils.hash_cfg import hash_password, verify_password router = APIRouter(prefix="/users", tags=["users"]) @@ -41,3 +42,53 @@ async def update_description( await session.refresh(profile) return {"description": profile.description} + + +@router.patch("/email") +async def change_email( + data: ChangeEmail = Body(...), + user: User = Depends(get_current_user), + session: AsyncSession = Depends(get_async_session), +): + user.email = data.email + + session.add(user) + await session.commit() + await session.refresh(user) + + return {"email": user.email} + + +@router.patch("/password") +async def change_password( + data: ChangePassword = Body(...), + user: User = Depends(get_current_user), + session: AsyncSession = Depends(get_async_session), +): + if not user.password: + raise HTTPException(status_code=400, detail="User has no password set") + + if not verify_password(data.current_password, user.password): + raise HTTPException( + status_code=400, + detail="Invalid current password", + ) + + if verify_password(data.new_password, user.password): + raise HTTPException( + status_code=400, + detail="New password must be different from current password", + ) + + hashed = hash_password(data.new_password) + + user.password = hashed + + session.add(user) + await session.commit() + await session.refresh(user) + + return { + "success": True, + "message": "Password updated successfully", + } diff --git a/app/schemas/user.py b/app/schemas/user.py index 5d60e2c..9f67ff1 100644 --- a/app/schemas/user.py +++ b/app/schemas/user.py @@ -38,3 +38,14 @@ class UserRead(BaseModel): class MeResponse(BaseModel): authenticated: bool user: Optional[UserRead] = None + + +class ChangeEmail(BaseModel): + email: EmailStr + password: str + + +class ChangePassword(BaseModel): + current_password: str = Field(..., min_length=8) + new_password: str = Field(..., min_length=8) + repeat_password: str = Field(..., min_length=8) -- cgit v1.3-3-g829e