feat: add PUT /api/auth/profile endpoint for self-service profile update

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
CCS Admin 2026-02-26 09:37:17 +00:00
parent 6bc0b3ac5a
commit 1fa5d20d40
2 changed files with 58 additions and 1 deletions

View file

@ -16,7 +16,7 @@ from app.schemas.auth import (
RegisterRequest, RegisterRequest,
TokenResponse, TokenResponse,
) )
from app.schemas.user import UserResponse from app.schemas.user import ProfileUpdate, UserResponse
from app.services.auth_service import ( from app.services.auth_service import (
activate_mfa, activate_mfa,
authenticate_user, authenticate_user,
@ -26,6 +26,7 @@ from app.services.auth_service import (
register_user, register_user,
revoke_refresh_token, revoke_refresh_token,
setup_mfa, setup_mfa,
update_profile,
) )
router = APIRouter() router = APIRouter()
@ -150,3 +151,15 @@ def change_password_endpoint(
def me(current_user: User = Depends(get_current_user)): def me(current_user: User = Depends(get_current_user)):
"""Return the currently authenticated user's profile.""" """Return the currently authenticated user's profile."""
return UserResponse.model_validate(current_user) return UserResponse.model_validate(current_user)
@router.put("/profile", response_model=UserResponse)
def update_profile_endpoint(
data: ProfileUpdate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Update the authenticated user's profile."""
update_data = data.model_dump(exclude_unset=True)
user = update_profile(db, current_user, **update_data)
return UserResponse.model_validate(user)

View file

@ -275,3 +275,47 @@ def change_password(
user.password_hash = hash_password(new_password) user.password_hash = hash_password(new_password)
user.must_change_password = False user.must_change_password = False
db.commit() db.commit()
# ---------------------------------------------------------------------------
# Profile update
# ---------------------------------------------------------------------------
def update_profile(
db: Session,
user: User,
username: str | None = None,
email: str | None = None,
first_name: str | None = None,
last_name: str | None = None,
display_name: str | None = None,
) -> User:
"""Update the authenticated user's own profile fields."""
if username and username != user.username:
existing = db.query(User).filter(User.username == username, User.id != user.id).first()
if existing:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail="Username already taken",
)
user.username = username
if email and email != user.email:
existing = db.query(User).filter(User.email == email, User.id != user.id).first()
if existing:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail="Email already taken",
)
user.email = email
if first_name is not None:
user.first_name = first_name
if last_name is not None:
user.last_name = last_name
if display_name is not None:
user.display_name = display_name
db.commit()
db.refresh(user)
return user