From f21b76df1edd2932df81557c1655661d40957882 Mon Sep 17 00:00:00 2001 From: Saurabh vishwakarma Date: Wed, 4 Jun 2025 00:32:28 +0530 Subject: [PATCH 1/3] refactor: updated swagger ui docs and improved comments --- server/pin_sphere/users/endpoint.py | 151 ++++++++++++++++------------ server/pin_sphere/users/service.py | 4 + 2 files changed, 92 insertions(+), 63 deletions(-) diff --git a/server/pin_sphere/users/endpoint.py b/server/pin_sphere/users/endpoint.py index 9c26ce9..aceae5d 100644 --- a/server/pin_sphere/users/endpoint.py +++ b/server/pin_sphere/users/endpoint.py @@ -8,12 +8,7 @@ from core.database.session_manager import get_async_session from core.models import User from core.types import FileContentType -from pin_sphere.users.service import get_user_by_username - -from . import service -from .filters import SettingsFilter -from .schemas import UserResponse, UserUpdate -from .service import delete_user, get_user, get_users, update_user +from . import filters, schemas, service # Create an API router for users-related endpoints router = APIRouter( @@ -24,29 +19,31 @@ @router.get( "/me", - response_model=UserResponse, - summary="Get current user", + response_model=schemas.UserResponse, + summary="Get current user profile", + description="Retrieve the profile information of the currently authenticated user.", tags=["Account Operations"], ) async def get_me( - current_user: User = Depends(auth.get_current_user), - session: AsyncSession = Depends(get_async_session), + current_user: User = Depends(auth.get_current_user), + session: AsyncSession = Depends(get_async_session), ): - return await get_user(session, current_user.username) + """Get current authenticated user's profile""" + return await service.get_user(session, current_user.username) -# Fetch all users with optional pagination @router.get( "", - response_model=list[UserResponse], - summary="Fetch all users", + response_model=list[schemas.UserResponse], + summary="List all users", + description="Fetch a paginated list of all users in the system.", tags=["Account Operations"], + dependencies=[Depends(auth.get_current_user)], ) async def read_users( - skip: int = 0, - limit: int = 10, - db: AsyncSession = Depends(get_async_session), - current_user: User = Depends(auth.get_current_user), + skip: int = 0, + limit: int = 10, + db: AsyncSession = Depends(get_async_session), ): """ Fetch a list of users with optional pagination. @@ -54,62 +51,79 @@ async def read_users( - **skip**: Number of records to skip (default: 0) - **limit**: Maximum number of records to return (default: 10) """ - users = await get_users(db, skip=skip, limit=limit) + # Fetch users with pagination + users = await service.get_users(db, skip=skip, limit=limit) return users @router.get( "/check-username/{username}", - summary="Check if a username is available", + summary="Check username availability", + description="Verify if a username is available for registration.", tags=["Account Operations"], + dependencies=[Depends(auth.get_current_user)], ) async def check_username_availability( - username: str, - db: AsyncSession = Depends(get_async_session), - current_user: User = Depends(auth.get_current_user), + username: str, + db: AsyncSession = Depends(get_async_session), ): """ Check if the provided username is available for registration. - - **username**: The username to check. + - **username**: The username to check for availability + + Returns success message if available, otherwise raises 400 error. """ - existing_user = await get_user_by_username(db, username=username) + # Check if username already exists + existing_user = await service.get_user_by_username(db, username=username) if existing_user: raise HTTPException(status_code=400, detail="Username already taken") return {"message": "Username is available"} -# Account deletion route @router.delete( "/{username}", - response_model=UserResponse, - summary="Delete an account by username", + response_model=schemas.UserResponse, + summary="Delete user account", + description="Delete a user account by username. Returns the deleted user information.", tags=["Account Operations"], + dependencies=[Depends(auth.get_current_user)], ) async def delete_account( - username: str, - db: AsyncSession = Depends(get_async_session), - current_user: User = Depends(auth.get_current_user), + username: str, + db: AsyncSession = Depends(get_async_session), ): """ - Delete the users account by their username. + Delete a user account by their username. - - **username**: The username of the users to delete. + - **username**: The username of the user to delete + + Returns the deleted user data or 404 if user not found. """ - user = await delete_user(db, username=username) + # Attempt to delete user + user = await service.delete_user(db, username=username) if not user: raise HTTPException(status_code=404, detail="User not found") return user @router.get( - "/upload_url", summary="Upload URL for profile photo", tags=["Account Operations"] + "/upload_url", + summary="Get profile photo upload URL", + description="Generate a pre-signed URL for uploading profile photos. Supports PNG and JPEG formats.", + tags=["Account Operations"] ) -async def retrive_upload_url( - ext: Literal["image/png", "image/jpeg"], - current_user: User = Depends(auth.get_current_user), +async def retrieve_upload_url( + ext: Literal["image/png", "image/jpeg"], + current_user: User = Depends(auth.get_current_user), ): + """ + Generate upload URL for profile photo. + + - **ext**: Image format (image/png or image/jpeg) + """ + # Convert extension and generate upload URL ext_ = FileContentType(ext) return service.get_upload_url(current_user, ext=ext_) @@ -117,20 +131,24 @@ async def retrive_upload_url( # Fetch a specific users by username @router.get( "/{username}", - response_model=UserResponse, - summary="Fetch a users by username", + response_model=schemas.UserResponse, + summary="Get user by username", + description="Retrieve a specific user's profile information by their username.", tags=["Account Operations"], ) async def read_user( - username: str, - db: AsyncSession = Depends(get_async_session), + username: str, + db: AsyncSession = Depends(get_async_session), ): """ - Fetch a single users by their unique username. + Fetch a single user by their unique username. + + - **username**: The username of the user to retrieve - - **username**: The username of the users to retrieve. + Returns user data or 404 if user not found. """ - user = await get_user(db, username=username) + # Fetch user by username + user = await service.get_user(db, username=username) if not user: raise HTTPException(status_code=404, detail="User not found") return user @@ -148,45 +166,52 @@ async def update_settings( # Update an existing users @router.put( "", - response_model=UserResponse, - summary="Update a user", + response_model=schemas.UserResponse, + summary="Update current user", + description="Update the current authenticated user's profile information (name, email, etc.).", tags=["Account Operations"], ) async def update_existing_user( - user_update: UserUpdate, - db: AsyncSession = Depends(get_async_session), - current_user: User = Depends(auth.get_current_user), + user_update: schemas.UserUpdate, + db: AsyncSession = Depends(get_async_session), + current_user: User = Depends(auth.get_current_user), ): """ - Update an existing users by their unique username. + Update the current user's profile information. + + - **user_update**: JSON payload containing the fields to update (name, email, etc.) - - **username**: The username of the users to update. - - **user_update**: JSON payload containing the fields to update (name, email). + Returns updated user data or 404 if user not found. """ - user = await update_user(db, current_user, user_update=user_update) + # Update current user's information + user = await service.update_user(db, current_user, user_update=user_update) if not user: raise HTTPException(status_code=404, detail="User not found") return user -# Delete a users by username +# Note: Duplicate delete endpoint - consider removing one of the delete methods @router.delete( "/{username}", - response_model=UserResponse, - summary="Delete a users", + response_model=schemas.UserResponse, + summary="Delete user by username", + description="Delete a user account by username. This is a duplicate endpoint.", tags=["Account Operations"], + dependencies=[Depends(auth.get_current_user)], ) async def delete_existing_user( - username: str, - db: AsyncSession = Depends(get_async_session), - current_user: User = Depends(auth.get_current_user), + username: str, + db: AsyncSession = Depends(get_async_session), ): """ - Delete a users by their unique username. + Delete a user by their unique username. + + - **username**: The username of the user to delete - - **username**: The username of the users to delete. + Returns deleted user data or 404 if user not found. """ - user = await delete_user(db, username=username) + # Delete user by username + user = await service.delete_user(db, username=username) if not user: raise HTTPException(status_code=404, detail="User not found") return user diff --git a/server/pin_sphere/users/service.py b/server/pin_sphere/users/service.py index 03844b5..d9cde90 100644 --- a/server/pin_sphere/users/service.py +++ b/server/pin_sphere/users/service.py @@ -130,3 +130,7 @@ async def update_settings(user: User, settings: SettingsFilter, session: AsyncSe .values(settings=old_settings) ) await session.commit() + + +async def get_settings(session: AsyncSession, current_user: User): + return ( await session.execute(select(User.settings).filter(User.username == current_user.username))).scalars().one() From 1349c6a6f19aa2d76d113b3c2594feb2a87e03e7 Mon Sep 17 00:00:00 2001 From: Saurabh vishwakarma Date: Wed, 4 Jun 2025 00:32:54 +0530 Subject: [PATCH 2/3] feat: Changed route position and added GET settings route --- server/pin_sphere/users/endpoint.py | 41 +++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/server/pin_sphere/users/endpoint.py b/server/pin_sphere/users/endpoint.py index aceae5d..0a933da 100644 --- a/server/pin_sphere/users/endpoint.py +++ b/server/pin_sphere/users/endpoint.py @@ -128,7 +128,36 @@ async def retrieve_upload_url( return service.get_upload_url(current_user, ext=ext_) -# Fetch a specific users by username +@router.get( + "/settings", + summary="Get user settings", + description="Retrieve the current user's account settings and preferences.", + tags=["Account Operations"], + response_model=filters.SettingsFilter +) +async def get_settings( + current_user: User = Depends(auth.get_current_user), + session: AsyncSession = Depends(get_async_session), +): + """Get current user's settings""" + return await service.get_settings(session, current_user) + + +@router.put( + "/settings", + status_code=status.HTTP_204_NO_CONTENT, + summary="Update user settings", + description="Update the current user's account settings and preferences." +) +async def update_settings( + current_user: User = Depends(auth.get_current_user), + settings: filters.SettingsFilter = Depends(), + session: AsyncSession = Depends(get_async_session), +): + """Update current user's settings""" + await service.update_settings(current_user, settings, session) + + @router.get( "/{username}", response_model=schemas.UserResponse, @@ -154,16 +183,6 @@ async def read_user( return user -@router.put("/settings", status_code=status.HTTP_204_NO_CONTENT) -async def update_settings( - current_user: User = Depends(auth.get_current_user), - settings: SettingsFilter = Depends(), - session: AsyncSession = Depends(get_async_session), -): - await service.update_settings(current_user, settings, session) - - -# Update an existing users @router.put( "", response_model=schemas.UserResponse, From f4fdb33743618b9abc4f191094381193ca0d0a66 Mon Sep 17 00:00:00 2001 From: Saurabh vishwakarma Date: Wed, 4 Jun 2025 00:38:26 +0530 Subject: [PATCH 3/3] format: fix formatting --- server/pin_sphere/users/endpoint.py | 53 +++++++++++++++-------------- server/pin_sphere/users/service.py | 10 +++++- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/server/pin_sphere/users/endpoint.py b/server/pin_sphere/users/endpoint.py index 0a933da..73be804 100644 --- a/server/pin_sphere/users/endpoint.py +++ b/server/pin_sphere/users/endpoint.py @@ -8,6 +8,7 @@ from core.database.session_manager import get_async_session from core.models import User from core.types import FileContentType + from . import filters, schemas, service # Create an API router for users-related endpoints @@ -25,8 +26,8 @@ tags=["Account Operations"], ) async def get_me( - current_user: User = Depends(auth.get_current_user), - session: AsyncSession = Depends(get_async_session), + current_user: User = Depends(auth.get_current_user), + session: AsyncSession = Depends(get_async_session), ): """Get current authenticated user's profile""" return await service.get_user(session, current_user.username) @@ -41,9 +42,9 @@ async def get_me( dependencies=[Depends(auth.get_current_user)], ) async def read_users( - skip: int = 0, - limit: int = 10, - db: AsyncSession = Depends(get_async_session), + skip: int = 0, + limit: int = 10, + db: AsyncSession = Depends(get_async_session), ): """ Fetch a list of users with optional pagination. @@ -64,8 +65,8 @@ async def read_users( dependencies=[Depends(auth.get_current_user)], ) async def check_username_availability( - username: str, - db: AsyncSession = Depends(get_async_session), + username: str, + db: AsyncSession = Depends(get_async_session), ): """ Check if the provided username is available for registration. @@ -91,8 +92,8 @@ async def check_username_availability( dependencies=[Depends(auth.get_current_user)], ) async def delete_account( - username: str, - db: AsyncSession = Depends(get_async_session), + username: str, + db: AsyncSession = Depends(get_async_session), ): """ Delete a user account by their username. @@ -112,11 +113,11 @@ async def delete_account( "/upload_url", summary="Get profile photo upload URL", description="Generate a pre-signed URL for uploading profile photos. Supports PNG and JPEG formats.", - tags=["Account Operations"] + tags=["Account Operations"], ) async def retrieve_upload_url( - ext: Literal["image/png", "image/jpeg"], - current_user: User = Depends(auth.get_current_user), + ext: Literal["image/png", "image/jpeg"], + current_user: User = Depends(auth.get_current_user), ): """ Generate upload URL for profile photo. @@ -133,11 +134,11 @@ async def retrieve_upload_url( summary="Get user settings", description="Retrieve the current user's account settings and preferences.", tags=["Account Operations"], - response_model=filters.SettingsFilter + response_model=filters.SettingsFilter, ) async def get_settings( - current_user: User = Depends(auth.get_current_user), - session: AsyncSession = Depends(get_async_session), + current_user: User = Depends(auth.get_current_user), + session: AsyncSession = Depends(get_async_session), ): """Get current user's settings""" return await service.get_settings(session, current_user) @@ -147,12 +148,12 @@ async def get_settings( "/settings", status_code=status.HTTP_204_NO_CONTENT, summary="Update user settings", - description="Update the current user's account settings and preferences." + description="Update the current user's account settings and preferences.", ) async def update_settings( - current_user: User = Depends(auth.get_current_user), - settings: filters.SettingsFilter = Depends(), - session: AsyncSession = Depends(get_async_session), + current_user: User = Depends(auth.get_current_user), + settings: filters.SettingsFilter = Depends(), + session: AsyncSession = Depends(get_async_session), ): """Update current user's settings""" await service.update_settings(current_user, settings, session) @@ -166,8 +167,8 @@ async def update_settings( tags=["Account Operations"], ) async def read_user( - username: str, - db: AsyncSession = Depends(get_async_session), + username: str, + db: AsyncSession = Depends(get_async_session), ): """ Fetch a single user by their unique username. @@ -191,9 +192,9 @@ async def read_user( tags=["Account Operations"], ) async def update_existing_user( - user_update: schemas.UserUpdate, - db: AsyncSession = Depends(get_async_session), - current_user: User = Depends(auth.get_current_user), + user_update: schemas.UserUpdate, + db: AsyncSession = Depends(get_async_session), + current_user: User = Depends(auth.get_current_user), ): """ Update the current user's profile information. @@ -219,8 +220,8 @@ async def update_existing_user( dependencies=[Depends(auth.get_current_user)], ) async def delete_existing_user( - username: str, - db: AsyncSession = Depends(get_async_session), + username: str, + db: AsyncSession = Depends(get_async_session), ): """ Delete a user by their unique username. diff --git a/server/pin_sphere/users/service.py b/server/pin_sphere/users/service.py index d9cde90..dc849f0 100644 --- a/server/pin_sphere/users/service.py +++ b/server/pin_sphere/users/service.py @@ -133,4 +133,12 @@ async def update_settings(user: User, settings: SettingsFilter, session: AsyncSe async def get_settings(session: AsyncSession, current_user: User): - return ( await session.execute(select(User.settings).filter(User.username == current_user.username))).scalars().one() + return ( + ( + await session.execute( + select(User.settings).filter(User.username == current_user.username) + ) + ) + .scalars() + .one() + )