fix(internal_user_endpoints.py): delete member from team table on /user/delete (#12926)

removes user from team when user is deleted
This commit is contained in:
Krish Dholakia
2025-07-24 16:42:28 -07:00
committed by GitHub
parent 1a57875d24
commit 8aa4beff5f
3 changed files with 70 additions and 26 deletions
@@ -1403,6 +1403,9 @@ async def delete_user(
Parameters:
- user_ids: List[str] - The list of user id's to be deleted.
"""
from litellm.proxy.management_endpoints.team_endpoints import (
_cleanup_members_with_roles,
)
from litellm.proxy.proxy_server import (
create_audit_log_for_update,
litellm_proxy_admin_name,
@@ -1451,6 +1454,34 @@ async def delete_user(
)
)
## CLEANUP MEMBERS_WITH_ROLES
fetch_all_teams = await prisma_client.db.litellm_teamtable.find_many(
where={"team_id": {"in": user_row.teams}}
)
teams_to_update = []
for team in fetch_all_teams:
is_member_in_team, new_team_members = _cleanup_members_with_roles(
existing_team_row=LiteLLM_TeamTable(**team.model_dump()),
data=TeamMemberDeleteRequest(
team_id=team.team_id,
user_id=user_row.user_id,
user_email=user_row.user_email,
),
)
if is_member_in_team:
_db_new_team_members: List[dict] = [
m.model_dump() for m in new_team_members
]
team.members_with_roles = json.dumps(_db_new_team_members)
teams_to_update.append(team)
## update teams
for team in teams_to_update:
await prisma_client.db.litellm_teamtable.update(
where={"team_id": team.team_id},
data={"members_with_roles": team.members_with_roles},
)
# End of Audit logging
## DELETE ASSOCIATED KEYS
@@ -1468,6 +1499,11 @@ async def delete_user(
where={"user_id": {"in": data.user_ids}}
)
## DELETE ASSOCIATED TEAM MEMBERSHIPS
await prisma_client.db.litellm_teammembership.delete_many(
where={"user_id": {"in": data.user_ids}}
)
## DELETE USERS
deleted_users = await prisma_client.db.litellm_usertable.delete_many(
where={"user_id": {"in": data.user_ids}}
@@ -1274,6 +1274,32 @@ async def team_member_add(
)
def _cleanup_members_with_roles(
existing_team_row: LiteLLM_TeamTable,
data: TeamMemberDeleteRequest,
) -> Tuple[bool, List[Member]]:
"""Cleanup members_with_roles list for a team."""
is_member_in_team = False
new_team_members: List[Member] = []
for m in existing_team_row.members_with_roles:
if (
data.user_id is not None
and m.user_id is not None
and data.user_id == m.user_id
):
is_member_in_team = True
continue
elif (
data.user_email is not None
and m.user_email is not None
and data.user_email == m.user_email
):
is_member_in_team = True
continue
new_team_members.append(m)
return is_member_in_team, new_team_members
@router.post(
"/team/member_delete",
tags=["team management"],
@@ -1346,24 +1372,10 @@ async def team_member_delete(
)
## DELETE MEMBER FROM TEAM
is_member_in_team = False
new_team_members: List[Member] = []
for m in existing_team_row.members_with_roles:
if (
data.user_id is not None
and m.user_id is not None
and data.user_id == m.user_id
):
is_member_in_team = True
continue
elif (
data.user_email is not None
and m.user_email is not None
and data.user_email == m.user_email
):
is_member_in_team = True
continue
new_team_members.append(m)
is_member_in_team, new_team_members = _cleanup_members_with_roles(
existing_team_row=existing_team_row,
data=data,
)
if not is_member_in_team:
raise HTTPException(status_code=400, detail={"error": "User not found in team"})
+4 -8
View File
@@ -3370,9 +3370,7 @@ class Router:
):
def sync_wrapper(
custom_llm_provider: Optional[
str
] = None,
custom_llm_provider: Optional[str] = None,
client: Optional[Any] = None,
**kwargs,
):
@@ -3384,9 +3382,7 @@ class Router:
# Handle asynchronous call types
async def async_wrapper(
custom_llm_provider: Optional[
str
] = None,
custom_llm_provider: Optional[str] = None,
client: Optional[Any] = None,
**kwargs,
):
@@ -3451,7 +3447,7 @@ class Router:
)
return async_wrapper
async def _init_vector_store_api_endpoints(
self,
original_function: Callable,
@@ -5021,7 +5017,7 @@ class Router:
return deployment
except Exception as e:
if self.ignore_invalid_deployments:
verbose_router_logger.warning(
verbose_router_logger.debug(
f"Error upserting deployment: {e}, ignoring and continuing with other deployments."
)
return None