feat: Add user profile management and password change endpoints
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user