feat: Add user profile management and password change endpoints
Some checks failed
Backend CI / lint (push) Failing after 4m51s
Backend CI / test (push) Successful in 3m38s

This commit is contained in:
JSC
2025-08-09 23:43:20 +02:00
parent 9e07ce393f
commit 0a8b50a0be
4 changed files with 195 additions and 0 deletions

View File

@@ -20,6 +20,8 @@ from app.schemas.auth import (
ApiTokenRequest,
ApiTokenResponse,
ApiTokenStatusResponse,
ChangePasswordRequest,
UpdateProfileRequest,
UserLoginRequest,
UserRegisterRequest,
UserResponse,
@@ -446,3 +448,85 @@ async def revoke_api_token(
) from e
else:
return {"message": "API token revoked successfully"}
# Profile management endpoints
@router.patch("/me")
async def update_profile(
request: UpdateProfileRequest,
current_user: Annotated[User, Depends(get_current_active_user)],
auth_service: Annotated[AuthService, Depends(get_auth_service)],
) -> UserResponse:
"""Update the current user's profile."""
try:
updated_user = await auth_service.update_user_profile(
current_user, request.model_dump(exclude_unset=True)
)
return await auth_service.user_to_response(updated_user)
except Exception as e:
logger.exception("Failed to update profile for user: %s", current_user.email)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to update profile",
) from e
@router.post("/change-password")
async def change_password(
request: ChangePasswordRequest,
current_user: Annotated[User, Depends(get_current_active_user)],
auth_service: Annotated[AuthService, Depends(get_auth_service)],
) -> dict[str, str]:
"""Change the current user's password."""
# Store user email before operations to avoid session detachment issues
user_email = current_user.email
try:
await auth_service.change_user_password(
current_user, request.current_password, request.new_password
)
return {"message": "Password changed successfully"}
except ValueError as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e),
) from e
except Exception as e:
logger.exception("Failed to change password for user: %s", user_email)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to change password",
) from e
@router.get("/user-providers")
async def get_user_providers(
current_user: Annotated[User, Depends(get_current_active_user)],
auth_service: Annotated[AuthService, Depends(get_auth_service)],
) -> list[dict[str, str]]:
"""Get the current user's connected authentication providers."""
providers = []
# Add password provider if user has password
if current_user.password_hash:
providers.append({
"provider": "password",
"display_name": "Password",
"connected_at": current_user.created_at.isoformat(),
})
# Get OAuth providers from the database
oauth_providers = await auth_service.get_user_oauth_providers(current_user)
for oauth in oauth_providers:
display_name = oauth.provider.title() # Capitalize first letter
if oauth.provider == "github":
display_name = "GitHub"
elif oauth.provider == "google":
display_name = "Google"
providers.append({
"provider": oauth.provider,
"display_name": display_name,
"connected_at": oauth.created_at.isoformat(),
})
return providers