From f6c6d96c02366be79e270e69ee1f3b3ed930f4ba Mon Sep 17 00:00:00 2001 From: Esa Kataja Date: Fri, 16 May 2025 12:18:10 +0300 Subject: [PATCH] Add user update ability --- src/models/user.py | 13 +++++++----- src/routes/users.py | 48 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/src/models/user.py b/src/models/user.py index da05e82..a8451be 100644 --- a/src/models/user.py +++ b/src/models/user.py @@ -26,7 +26,7 @@ class User(UserBase): updated_at: datetime = Field( description="Last update timestamp", examples=["2025-01-01T00:00:00.000Z"] ) - + @property def has_logged_in(self) -> bool: """Returns True if the user has ever logged in, False if last_login is the epoch date.""" @@ -46,9 +46,12 @@ class UserLogin(UserBase): password: str = Field(description="Password of the user", examples=["sn1rbul4"]) -class UserChangePassword(BaseModel): +class UpdateUser(BaseModel): id: int = Field(description="ID of the user", examples=[1]) - old_password: str = Field( - description="Old password of the user", examples=["sn1rbul4"] + avatar_id: int | None = Field(None, description="ID of the avatar", examples=[1]) + email: str | None = Field( + None, description="Email of the user", examples=["kalle@kalle.com"] + ) + password: str | None = Field( + None, description="Password of the user", examples=["p1p4l1"] ) - password: str = Field(description="Password of the user", examples=["p1p4l1"]) diff --git a/src/routes/users.py b/src/routes/users.py index 7c624d5..99b32a7 100644 --- a/src/routes/users.py +++ b/src/routes/users.py @@ -1,8 +1,11 @@ from fastapi import APIRouter, HTTPException, Request -from models.user import User, UserChangePassword +from models.user import User, UpdateUser +from models.msg import Message from lib.db import get_connection from lib.logger import logger +from lib.helpers import hash_password +from datetime import datetime router = APIRouter(prefix="/users", tags=["users"]) @@ -37,11 +40,40 @@ async def get_user(user_id: int, request: Request): return User(**user_data) -@router.patch("/{user_id}") -async def change_password(user_id: int, user: UserChangePassword, request: Request): - logger.info( - f"Password change attempt for user_id: {user_id} from {request.client.host}" +@router.patch("/", response_model=Message) +async def update_user(user: UpdateUser, request: Request): + logger.info(f"Update attempt for user_id: {user.id} from {request.client.host}") + user_id = user.id + avatar_id = user.avatar_id if user.avatar_id else None + email = user.email if user.email else None + password = hash_password(user.password) if user.password else None + updated_at = datetime.now() + + with get_connection() as conn: + # Build query dynamically based on non-None values + update_fields = [] + params = [] + + if avatar_id is not None: + update_fields.append("avatar_id = ?") + params.append(avatar_id) + + if email is not None: + update_fields.append("email = ?") + params.append(email) + + if password is not None: + update_fields.append("password = ?") + params.append(password) + + # Only proceed if there are fields to update + if update_fields: + query = f'UPDATE "User" SET {", ".join(update_fields)}, updated_at = ? WHERE id = ?' + params.append(updated_at) + params.append(user_id) + conn.execute(query, params) + + logger.debug( + f"User updated successfully: {user_id}, avatar_id: {avatar_id}, email: {email}, password: {password}" ) - # Implementation will go here when completed - logger.warning(f"Password change not implemented for user_id: {user_id}") - raise HTTPException(status_code=401, detail="Not implemented") + return Message(type="success", message="User updated successfully")