Ë
    tPêjòÊ ã                   ó   — U d Z ddlZddlZddlZddlmZmZmZ ddlmZm	Z	 ddl
mZmZmZmZ ddlZddlmZmZmZmZmZmZ ddlZddlmZ ddlmZ dd	l­ dd
lmZmZ ddlm Z  ddl!m"Z"m#Z# ddl$m%Z% ddl&m'Z' ddl(m)Z)m*Z*m+Z+ ddl,m-Z-m.Z.m/Z/m0Z0m1Z1 ddl2m3Z3m4Z4m5Z5 ddl6m7Z7m8Z8 ddl9m:Z: ddl;m<Z<m=Z= ddl>m?Z? ddl@mAZA ddlBmCZCmDZDmEZE ddlFmGZG ddlHmIZI ddlJmKZK ddlLmMZM ddlNmOZOmPZPmQZQmRZR ddlSmTZTmUZUmVZV eWrddlXmYZZ ddlXm[Z\ dd l!m]Z] dd!l^m_Z_ dd"l;m`Z`  e«       Zaeebd#<   	 	 	 	 dÏd'„Zc	 	 	 	 dÐd(„Zd	 	 	 	 dÑd)„Ze	 	 	 	 dÒd*„Zf	 	 	 	 dÓd+„Zg	 	 	 	 dÔd,„Zh	 	 	 	 dÕd-„Zid.ejd&dfd/„ZkdÖd0„Zld1ejd.emd&ejfd2„Znd3dd4œd5eod6eodz  d$d%d7epd8eodz  d&dfd9„Zqd:eodz  d$d%d&dfd;„Zrd<eodz  d$d%d&dfd=„Zsd<eod>eteo   d$d?d@eufdA„Zv	 	 	 d×d<eodBeod@eud:eodz  dCewdz  dDedE   fdF„Zxd&eteo   etey   z  dz  fdG„Zzd<eod:eodz  d@eudHeteo   etey   z  d$d?f
dI„Z{eajù                  dJdKg ee «      ge}¬L«      e: ee «      fd.emd@eufdM„«       «       Z~eajÿ                  dNdKgd3 ee «      g¬O«       ee «      fd@eufdP„«       Z€dQete�   ete‚   z  dz  dBeod&e�eƒz  dz  fdR„Z„d<eod&epfdS„Z…dTed&eodz  fdU„Z†dTed<eodz  d&eodz  fdV„Z‡d<eodz  d@eud&dfdW„Zˆd$ed<eodz  dXedz  d@eud&e‰ete‚   ete‚   dz  f   f
dY„ZŠ e‹eTeUeVh«      ZŒeebdZ<   d[ejeoe�f   dz  d&ejeoe�f   dz  fd\„ZŽ	 dØd<eodz  dXedz  d]ete�   dz  dQete‚   d^ete‚   dz  d_ejeoejeoe�f   f   dz  d&e�fd`„Z‘eajÿ                  dadKg ee «      ge�¬L«      e: e�j$                  ddb¬c«       ee «      fdTed<eodz  d@eufdd„«       «       Z“d@eudeeod&dffdg„Z”eajÿ                  dhdKg ee «      ge•¬L«      e: e�j$                  ddb¬c«       ee «      fdTed<eodz  d@eufdi„«       «       Z–d@eufdj„Z—d]ete�   dz  dkete�   ete‚   z  dz  fdl„Z˜d1ejd.e™ešz  d&ejfdm„Z›dnejeoef   doeœdz  dpeodz  d@eudqeodz  d&dfdr„Z�dse™d@eudoeœdz  d&dfdt„Zždueeoe�f   d&dfdv„ZŸdse™d&epfdw„Z d<eodz  dxe‰eodyf   d&dfdz„Z¡	 dØdse™d@eudpeodz  d&ejeoef   fd{„Z¢d@eudXe£d&epfd|„Z¤eajù                  d}dKg ee «      g¬~«      e: ee «      fd.e™d@eufd„«       «       Z¥	 dØd€ete™   d@eudpeodz  d&ePfd�„Z¦eajù                  d‚dKg ee «      geP¬L«      e: ee «       eddƒ¬„«      fd.eOd@eudpeodz  fd…„«       «       Z§	 dØd$d%d†eteo   dz  d&eeoe¨f   fd‡„Z©dˆeodz  d‰eod&ejeoeof   dz  fdŠ„Zªd@eud‹eodz  d$d%dŒd�dŽd�d&eodz  fd�„Z«eajÿ                  d‘dKg ee «      geQ¬L«       e�j$                  dd’¬c«       e�j$                  dd“¬c«       e�j$                  dd”¬c«       e�j$                  dd•¬c«       e�j$                  dd–¬c«       e�j$                  d—d—d˜¬™«       e�j$                  dšd—d›dœ¬�«       e�j$                  ddž¬c«       e�j$                  dŸd ¬c«       e�j$                  dd¡¬c«       ee «      fd¢eodz  d†eodz  d£eodz  d:eodz  d¤eodz  d¥e¨d¦e¨dˆeodz  d‰eod‹eodz  d@eufd§„«       Z¬eajù                  d¨dKg ee «      g¬~«      e: ee «       eddƒ¬„«      fd.e­d@eudpeodz  fd©„«       «       Z®d<eodªeodDe¯d&d«fd¬„Z°d@eudBeodz  d$d%dŒd�dŽd�d&eteo   dz  fd­„Z±d@eudBeod$d%dŒd�dŽd�d&eteo   fd®„Z²eajÿ                  d¯dKg ee «      gd3d°d±ete³   ii¬²«       e�j$                  ddb¬c«       e�j$                  dd³¬c«       e�j$                  dd´¬c«       e�j$                  d—dµd—¬¶«       e�j$                  d·dœd—d›¬¸«       ee «      fd<eodz  d:eodz  dBeodz  d¥e¨d¦e¨d@eufd¹„«       Z´d$d?dºee)   d&ejeoejf   fd»„Zµeajÿ                  d¼d½dKg ee «      geM¬L«      e: e�j$                  dd¾¬c«       e�j$                  dd¿¬c«       e�j$                  ddÀ¬c«       e�j$                  ddÁ¬c«       e�j$                  ddÂ¬c«       e�j$                  d—dµd—¬¶«       e�j$                  d·dÃd—dÄ¬¸«       e�j$                  ddÅ¬c«       e�j$                  d3dÆ¬c«       ee «      f
dÇeodz  dÈeodz  d±eodz  dÉeodz  d<eodz  d¥e¨d¦e¨dÊe¨dz  dËepd@eud&eMfdÌ„«       «       Z¶eajÿ                  dÍd½dKg ee «      geM¬L«      e: e�j$                  dd¾¬c«       e�j$                  dd¿¬c«       e�j$                  ddÀ¬c«       e�j$                  ddÁ¬c«       e�j$                  ddÂ¬c«       e�j$                  ddÅ¬c«       e�j$                  d3dÆ¬c«       ee «      fdÇeodz  dÈeodz  d±eodz  dÉeodz  d<eodz  dÊe¨dz  dËepd@eud&eMfdÎ„«       «       Z·y)Ùzš
Internal User Management Endpoints


These are members of a Team on LiteLLM

/user/new
/user/update
/user/bulk_update
/user/delete
/user/info
/user/list
é    N)Ú	AwaitableÚMappingÚSequence)ÚdatetimeÚtimezone)ÚAnyÚFinalÚLiteralÚcast)Ú	APIRouterÚDependsÚHeaderÚHTTPExceptionÚRequestÚstatus)Úverbose_proxy_logger)Úuuid)Ú*)Úget_team_objectÚget_user_object)Úuser_api_key_auth)Úobject_permission_cache_keyÚ#user_object_permission_id_cache_key)Úbuild_model_max_budget_usage)ÚUserManagementEventHooks)ÚDailySpendRecordÚget_daily_activityÚget_daily_activity_aggregated)Ú_is_user_team_adminÚ_user_has_admin_viewÚ$require_caller_user_id_for_non_adminÚvalidate_budget_durationÚvalidate_finite_spend)Ú$_check_permissions_caller_permissionÚgenerate_key_helper_fnÚprepare_metadata_fields)Ú_set_object_permissionÚ&handle_update_object_permission_common)Úmanagement_endpoint_wrapper)Úhandle_exception_on_proxyÚhash_password)ÚOrganizationRepository)ÚTableActions)ÚInvitationLinkRepositoryÚ OrganizationMembershipRepositoryÚTeamMembershipRepository)ÚTeamRepository)ÚUserRepository)ÚVerificationTokenRepository)ÚSpendAnalyticsPaginatedResponse)ÚBulkUpdateUserRequestÚBulkUpdateUserResponseÚUserListResponseÚUserUpdateResult)ÚSCIM_ENTERPRISE_METADATA_KEYÚSCIM_ENTITLEMENTS_METADATA_KEYÚSCIM_ROLES_METADATA_KEY)Úmodels)Útypes)ÚUserApiKeyCache)ÚPrismaClient)ÚProxyLoggingÚrouterÚprisma_clientúPrismaClient | NoneÚreturnc                 ó0   — t        | «      j                  }|S ©N)r2   Útable)rB   Ú
user_tables     ú/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/management_endpoints/internal_user_endpoints.pyÚ_user_tablerJ   b   ó   € ô HVÐVcÓGd×GjÑGj€JØÐó    c                 ó0   — t        | «      j                  }|S rF   )r1   rG   )rB   Ú
team_tables     rI   Ú_team_tablerO   i   rK   rL   c                 ó0   — t        | «      j                  }|S rF   )r3   rG   )rB   Útoken_tables     rI   Ú_verification_token_tablerR   p   s$   € ô QlØóQç�eð ð ÐrL   c                 ó0   — t        | «      j                  }|S rF   )r/   rG   )rB   Úmembership_tables     rI   Ú_organization_membership_tablerU   y   s   € ô 	)¨Ó7×=Ñ=ð ð ÐrL   c                 ó0   — t        | «      j                  }|S rF   )r.   rG   )rB   Úinvitation_tables     rI   Ú_invitation_link_tablerX   ‚   s$   € ô SkØóSç�eð ð ÐrL   c                 ó0   — t        | «      j                  }|S rF   )r,   rG   )rB   Úorganization_tables     rI   Ú_organization_tabler[   ‹   s$   € ô XnØóXç�eð ð ÐrL   c                 ó0   — t        | «      j                  }|S rF   )r0   rG   )rB   Úteam_membership_tables     rI   Ú_team_membership_tabler^   ”   s$   € ô XpØóXç�eð ð !Ð rL   Údatac                 ó<   — d| v r| d   �t        | d   «      | d<   yyy)z(Hash password field in-place if present.ÚpasswordN)r+   ©r_   s    rI   Ú_hash_password_in_dictrc   �   s0   € à�TÑ˜d :Ñ.Ð:Ü(¨¨jÑ)9Ó:ˆˆZÒð ;ÐrL   c                 ó*  — t        | t        «      rƒ| j                  dd«       t        | j                  d«      t        «      r| d   j                  dd«       yt	        | j                  d«      d«      r | d   j
                  j                  dd«       yyy)zRStrip password from API response (handles dicts, nested dicts, and Prisma models).ra   Nr_   Ú__dict__)Ú
isinstanceÚdictÚpopÚgetÚhasattrre   )Úresponses    rI   Ú_strip_password_from_responserl   £   sz   € ä�(œDÔ!Ø�‰�Z Ô&Ü�h—l‘l 6Ó*¬DÔ1Ø�VÑ× Ñ  ¨TÕ2Ü�X—\‘\ &Ó)¨:Ô6Ø�VÑ×%Ñ%×)Ñ)¨*°dÕ;ð 7ð	 "rL   Ú	data_jsonc                 ó\  — d| v r%| d   € t        t        j                  «       «      | d<   | j                  dd«      }|du rd| d<   t        j
                  rª|j                  t        j                  j                  k7  rƒ|j                  t        j                  k7  rft        j
                  j                  «       D ]E  \  }}|dk(  rŒ|| vs1| |   �,|dk(  sŒt        | |   t        «      sŒ/t        | |   «      d	k(  sŒA|| |<   ŒG |j                  ��|j                  t        j                  j                  k(  rht        j                  �$| j!                  d
«      €t        j                  | d
<   t        j"                  �$| j!                  d«      €t        j"                  | d<   | j                  dd «       | S )NÚuser_idÚauto_create_keyTFÚuserÚ
table_nameÚavailable_teamsr<   r   Ú
max_budgetÚbudget_durationÚteams)Ústrr   Úuuid4rh   ÚlitellmÚdefault_internal_user_paramsÚ	user_roleÚLitellmUserRolesÚPROXY_ADMINÚvalueÚitemsrf   ÚlistÚlenÚINTERNAL_USERÚmax_internal_user_budgetri   Úinternal_user_budget_duration)rm   r_   rp   Úkeyr~   s        rI   Ú _update_internal_new_user_paramsr†   ­   s}  € Ø�IÑ )¨IÑ"6Ð">Ü"¤4§:¡:£<Ó0ˆ	�)Ñà&Ÿ]™]Ð+<¸dÓC€Oà˜%ÑØ"(ˆ	�,Ñä×+Ò+Ø�‰Ô*×6Ñ6×<Ñ<Ò<ÀÇÁÔSc×SoÑSoÒAoä!×>Ñ>×DÑDÓFò 
	'‰JˆC�ØÐ'Ò'Øà˜9Ñ$Ø˜S‘>Ð)Ø˜(“?Ü˜y¨™~¬tÕ4Ü˜	 #™Ó'¨1Ó,à!&�	˜#’ð
	'ð ‡~�~Ð! d§n¡nÔ8H×8VÑ8V×8\Ñ8\Ò&\Ü×+Ñ+Ð7¸I¿M¹MÈ,Ó<WÐ<_Ü&-×&FÑ&FˆI�lÑ#ä×0Ñ0Ð<ÀÇÁÐO`ÓAaÐAiÜ+2×+PÑ+PˆIÐ'Ñ(à‡M�M�'˜4Ô ØÐrL   F)Úcase_insensitiveÚlabelÚ
field_nameÚfield_valuer‡   rˆ   c          	   ƒ   ó   K  — |r†|€t        d«      ‚|j                  «       }| d|ii}|rd||    d<   t        |«      j                  j	                  |¬«      ƒ d{  –—† }|�)t        || |«      }|xs | }	t        ddd	|	› d
|› d�i¬«      ‚yy7 Œ1­w)a,  
    Helper function to check if a field already exists in the user table.

    Args:
        field_name (str): Database field name to check.
        field_value (Optional[str]): Value to check for duplicates.
        prisma_client (Any): Database client instance.
        case_insensitive (bool): Whether to use case-insensitive comparison.
        label (Optional[str]): Human readable label for error messages.

    Raises:
        Exception: If database is not connected.
        HTTPException: If a user with the given field value already exists.
    NúDatabase not connectedÚequalsÚinsensitiveÚmode©Úwherei™  Úerrorz
User with ú z already exists©Ústatus_codeÚdetail)Ú	ExceptionÚstripr2   rG   Ú
find_firstÚgetattrr   )
r‰   rŠ   rB   r‡   rˆ   r~   Úwhere_clauseÚexisting_userÚexisting_valueÚerror_labels
             rI   Ú_check_duplicate_user_fieldrŸ   Ñ   sÄ   è ø€ ñ, ØÐ ÜÐ4Ó5Ð5à"×(Ñ(Ó*ˆØ)¨H°eÐ+<Ð=ˆÙØ/<ˆL˜Ñ$ VÑ,ä-;¸MÓ-J×-PÑ-P×-[Ñ-[ÐbnÐ-[Ó-o×'oˆàÐ$Ü$+¨M¸:ÀuÓ$MˆNØ!&Ò!4¨*ˆKÜØØ :¨k¨]¸!¸NÐ;KÈ?Ð![Ð\ôð ð %ð ð (pús   ‚ABÁBÁ2BÚ
user_emailc              ƒ   ó@   K  — t        d| |dd¬«      ƒ d{  –—†  y7 Œ­w)zR
    Helper function to check if a user email already exists in the database.
    r    TÚemail)r‰   rŠ   rB   r‡   rˆ   N©rŸ   )r    rB   s     rI   Ú_check_duplicate_user_emailr¤   û   s)   è ø€ ô &ØØØ#ØØô÷ ò ús   ‚–—ro   c              ƒ   ó>   K  — t        d| |d¬«      ƒ d{  –—†  y7 Œ­w)zO
    Helper function to check if a user id already exists in the database.
    ro   Úid)r‰   rŠ   rB   rˆ   Nr£   )ro   rB   s     rI   Ú_check_duplicate_user_idr§     s&   è ø€ ô &ØØØ#Øô	÷ ò ús   ‚•–Úorganizationsr?   Úuser_api_key_dictc              ƒ   ó   K  — ddl m} g }|D ]N  }|j                   |t        |t	        | t
        j                  ¬«      g¬«      t        dddœ¬«      |¬	«      «       ŒP t        j                  |d
diŽƒ d{  –—†  y7 Œ­w)z%
    Add a user to organizations
    r   )Úorganization_member_add)ro   Úrole)Úorganization_idÚmemberÚhttpú	/user/new©ÚtypeÚpath©Úscope)r_   Úhttp_requestr©   Úreturn_exceptionsTN)
Ú9litellm.proxy.management_endpoints.organization_endpointsr«   ÚappendÚOrganizationMemberAddRequestÚ	OrgMemberr|   r‚   r   ÚasyncioÚgather)ro   r¨   rB   r©   r«   Útasksr­   s          rI   Ú_add_user_to_organizationsr¿     s‰   è ø€ õð -/€EØ(ò 
ˆØ�‰Ù#Ü1Ø$3ä!Ø$+Ü!1×!?Ñ!?ôðôô %Ø#)°;Ñ?ôð #4ôõ	
ð
ô$ �.‰.˜%Ð
8°4Ñ
8×8Ò8ús   ‚A4A>Á6A<Á7A>Úteam_idÚmax_budget_in_teamr{   )rq   Úadminc           
   ƒ   óŒ  K  — ddl m} 	  |t        |t        | ||¬«      |¬«      |¬«      ƒ d {  –—†  y 7 Œ# t        $ rp}|j
                  dk(  r1dt        |«      v sdt        |«      v rt        j                  d	|«       n&t        j                  d
| |t        |«      «       Y d }~y Y d }~y d }~wt        $ rŠ}dt        |«      v s9dt        |«      v s,t        |t        «      r3t        j                  |j                  v rt        j                  d	|«       n#t        j                  d
| |t        |«      «       |‚Y d }~y d }~ww xY w­w)Nr   )Úteam_member_add)ro   r¬   r    )rÀ   r®   rÁ   ©r_   r©   é�  zalready existszdoesn't existzglitellm.proxy.management_endpoints.internal_user_endpoints.new_user(): User already exists in team - %szulitellm.proxy.management_endpoints.internal_user_endpoints._add_user_to_team(): failed to add user %s to team %s - %s)Ú1litellm.proxy.management_endpoints.team_endpointsrÄ   ÚTeamMemberAddRequestÚMemberr   r•   rw   r   Údebugr’   r—   rf   ÚProxyExceptionÚProxyErrorTypesÚteam_member_already_in_teamr²   )ro   rÀ   r©   r    rÁ   r{   rÄ   Úes           rI   Ú_add_user_to_teamrÏ   7  sA  è ø€ õ Rð.ÙÜ%ØÜØ#Ø"Ø)ôð
 $6ôð 0ô
÷ 	
ò 	
ùô ò Ø�=‰=˜CÒÐ%5¼¸Q»Ñ%?À?ÔVYÐZ[ÓV\ÑC\Ü ×&Ñ&ØyØõô
 !×&Ñ&ð8àØÜ�A“÷ñ ôûô ò à¤ A£Ñ&Ø¤# a£&Ñ(Ü˜!œ^Ô,Ü×;Ñ;¸q¿v¹vÑEä ×&Ñ&ØyØõô
 !×&Ñ&ð8àØÜ�A“ôð ˆGôûðüsK   ‚EŠ%7 ¯5°7 ´Eµ7 ·	EÁ A!B+Â!
EÂ+EÂ7B D<Ä7EÄ<EÅEc                  ó~  — t         j                  €y t         j                  j                  d«      } | �†t        d„ | D «       «      r| S t        d„ | D «       «      rJ| D �cg c]>  }t	        |j                  d«      |j                  d«      |j                  dd«      ¬«      ‘Œ@ c}S t        j                  d	| «       y c c}w )
Nrv   c              3   ó<   K  — | ]  }t        |t        «      –— Œ y ­wrF   ©rf   rw   ©Ú.0Úteams     rI   ú	<genexpr>z,check_if_default_team_set.<locals>.<genexpr>w  s   è ø€ Ò7¨Œz˜$¤×$Ñ7ùó   ‚c              3   ó<   K  — | ]  }t        |t        «      –— Œ y ­wrF   )rf   rg   rÓ   s     rI   rÖ   z,check_if_default_team_set.<locals>.<genexpr>y  s   è ø€ Ò:¨D”˜D¤$×'Ñ:ùr×   rÀ   rÁ   r{   rq   )rÀ   rÁ   r{   z5Invalid team type in default internal user params: %s)ry   rz   ri   ÚallÚNewUserRequestTeamr   r’   )rv   rÕ   s     rI   Úcheck_if_default_team_setrÛ   r  s¹   € Ü×+Ñ+Ð3ØÜ×7Ñ7×;Ñ;¸GÓD€EØÐÜÑ7°Ô7Ô7ØˆLÜÑ:°EÔ:Ô:ð "öð ô #Ø ŸH™H YÓ/Ø'+§x¡xÐ0DÓ'EØ"Ÿh™h {°FÓ;öòð ô !×&Ñ&ØGØôð ùòs   ÁAB:rv   c              ƒ   ób  K  — g }|D ]…  }d}d }t        |t        «      r|}	nLt        |t        «      r%|j                  }	|j                  }|j
                  }nt        dt        |«      › �«      ‚|j                  t        | |	||||¬«      «       Œ‡ t        j                  |ddiŽƒ d {  –—†  y 7 Œ­w)Nrq   zInvalid team type: )ro   rÀ   r    r©   rÁ   r{   r·   T)rf   rw   rÚ   rÀ   r{   rÁ   Ú
ValueErrorr²   r¹   rÏ   r¼   r½   )
ro   r    r©   rv   rB   r¾   rÕ   r{   rÁ   rÀ   s
             rI   Úadd_new_user_to_default_teamrÞ   Š  sµ   è ø€ ð -/€EØò 
ˆØ.4ˆ	Ø+/ÐÜ�dœCÔ Ø‰GÜ˜Ô0Ô1Ø—l‘lˆGØŸ™ˆIØ!%×!8Ñ!8ÑäÐ2´4¸³:°,Ð?Ó@Ð@à�‰ÜØØØ%Ø"3Ø#5Ø#ôõ		
ð
ô, �.‰.˜%Ð
8°4Ñ
8×8Ò8ús   ‚B%B/Â'B-Â(B/r°   zInternal User management)ÚtagsÚdependenciesÚresponse_modelc              ƒ   óz  K  — 	 ddl m}m} |€%t        dt        j
                  j                  ¬«      ‚|€%t        dt        j
                  j                  ¬«      ‚t        | j                  «       t        | j                  |«      ƒ d{  –—†  t        | j                  |«      ƒ d{  –—†  t        |«      j                  «       ƒ d{  –—† }|r|j                  |¬«      rt        dd	¬«      ‚| j                   t"        j$                  t"        j&                  fv rTt)        |t*        «      rD|j                   t"        j$                  k7  r't        dd
| j                   › d|j                   › �¬«      ‚t-        | |¬«       | j/                  «       }t1        || «      }t3        ||¬«      ƒ d{  –—† }t5        |«       | j6                  }|€
t9        «       }t;        t<        t>           dz  |jA                  dd«      «      }tC        dddi|¤Žƒ d{  –—† }|jE                  dd«      }	|	�AtG        t;        t>        |jE                  d«      «      |	|| j                  dd¬«      ƒ d{  –—†  nA|�?tI        t;        t>        |jE                  d«      «      | j                  |||¬«      ƒ d{  –—†  t;        t>        dz  |jE                  dd«      «      }
|�|
�tK        |
|||¬«      ƒ d{  –—†  ddg}i }|jM                  «       D ]"  \  }}|tN        jP                  v sŒ||vsŒ|||<   Œ$ |jE                  dd«      |d<   tN        jS                  |«      }tU        jV                  tY        jZ                  | ||¬«      «       |S 7 �Œë7 �ŒÐ7 �Œ²7 �ŒÖ7 �Œw7 �Œ&7 Œæ7 Œª# t\        $ r&}t_        j`                  d|«       tc        |«      ‚d}~ww xY w­w)a+  
    Use this to create a new INTERNAL user with a budget.
    Internal Users can access LiteLLM Admin UI to make keys, request access to models.
    This creates a new user and generates a new api key for the new user. The new api key is returned.

    Returns user id, budget + new key.

    Parameters:
    - user_id: Optional[str] - Specify a user id. If not set, a unique id will be generated.
    - user_alias: Optional[str] - A descriptive name for you to know who this user id refers to.
    - teams: Optional[list] - specify a list of team id's a user belongs to.
    - user_email: Optional[str] - Specify a user email.
    - send_invite_email: Optional[bool] - Specify if an invite email should be sent.
    - user_role: Optional[str] - Specify a user role - "proxy_admin", "proxy_admin_viewer", "internal_user", "internal_user_viewer", "team", "customer". Info about each role here: `https://github.com/BerriAI/litellm/litellm/proxy/_types.py#L20`
    - max_budget: Optional[float] - Specify max budget for a given user.
    - budget_duration: Optional[str] - Budget is reset at the end of specified duration. If not set, budget is never reset. You can set duration as seconds ("30s"), minutes ("30m"), hours ("30h"), days ("30d"), months ("1mo").
    - models: Optional[list] - Model_name's a user is allowed to call. (if empty, key is allowed to call all models). Set to ['no-default-models'] to block all model access. Restricting user to only team-based model access.
    - tpm_limit: Optional[int] - Specify tpm limit for a given user (Tokens per minute)
    - rpm_limit: Optional[int] - Specify rpm limit for a given user (Requests per minute)
    - auto_create_key: bool - Default=True. Flag used for returning a key as part of the /user/new response
    - aliases: Optional[dict] - Model aliases for the user - [Docs](https://litellm.vercel.app/docs/proxy/virtual_keys#model-aliases)
    - config: Optional[dict] - [DEPRECATED PARAM] User-specific config.
    - allowed_cache_controls: Optional[list] - List of allowed cache control values. Example - ["no-cache", "no-store"]. See all values - https://docs.litellm.ai/docs/proxy/caching#turn-on--off-caching-per-request-
    - blocked: Optional[bool] - [Not Implemented Yet] Whether the user is blocked.
    - guardrails: Optional[List[str]] - [Not Implemented Yet] List of active guardrails for the user
    - policies: Optional[List[str]] - List of policy names to apply to the user. Policies define guardrails, conditions, and inheritance rules.
    - permissions: Optional[dict] - [Not Implemented Yet] User-specific permissions, eg. turning off pii masking.
    - metadata: Optional[dict] - Metadata for user, store information for user. Example metadata = {"team": "core-infra", "app": "app2", "email": "ishaan@berri.ai" }
    - max_parallel_requests: Optional[int] - Rate limit a user based on the number of parallel requests. Raises 429 error, if user's parallel requests > x.
    - soft_budget: Optional[float] - Get alerts when user crosses given budget, doesn't block requests.
    - model_max_budget: Optional[dict] - Model-specific max budget for user. [Docs](https://docs.litellm.ai/docs/proxy/users#add-model-specific-budgets-to-keys)
    - budget_fallbacks: Optional[Dict[str, List[str]]] - Per-model fallback chain tried in order when that model's own `model_max_budget` is exceeded, e.g. {"gpt-4o": ["gpt-4o-mini"]}.
    - model_rpm_limit: Optional[float] - Model-specific rpm limit for user. [Docs](https://docs.litellm.ai/docs/proxy/users#add-model-specific-limits-to-keys)
    - mcp_rpm_limit: Optional[dict] - Per-MCP-server rpm limit, keyed by MCP server name {"github": 100, "slack": 200}. Enforced for keys and teams only; values set on a user are stored but not enforced per user.
    - tag_rpm_limit: Optional[dict] - Per-request-tag rpm limit, keyed by request tag {"cell-1": 1000, "cell-2": 500}. Enforced for keys only; values set on a user are stored but not enforced per user.
    - model_tpm_limit: Optional[float] - Model-specific tpm limit for user. [Docs](https://docs.litellm.ai/docs/proxy/users#add-model-specific-limits-to-keys)
    - spend: Optional[float] - Amount spent by user. Default is 0. Will be updated by proxy whenever user is used. You can set duration as seconds ("30s"), minutes ("30m"), hours ("30h"), days ("30d"), months ("1mo").
    - agent_id: Optional[str] - The agent id associated with the user.
    - team_id: Optional[str] - [DEPRECATED PARAM] The team id of the user. Default is None.
    - duration: Optional[str] - Duration for the key auto-created on `/user/new`. Default is None.
    - key_alias: Optional[str] - Alias for the key auto-created on `/user/new`. Default is None.
    - sso_user_id: Optional[str] - The id of the user in the SSO provider.
    - object_permission: Optional[LiteLLM_ObjectPermissionBase] - internal user-specific object permission. Example - {"vector_stores": ["vector_store_1"], "mcp_servers": ["github"], "mcp_tool_permissions": {"github": ["list_issues"]}}. The MCP grants act as a ceiling on every key this user holds. IF null or {} then no object permission.
    - prompts: Optional[List[str]] - List of allowed prompts for the user. If specified, the user will only be able to use these specific prompts.
    - organizations: List[str] - List of organization id's the user is a member of
    - budget_limits: Optional[list] - List of concurrent budget windows for the user. Each window specifies a budget_limit, time_period, and optional budget_duration. Example - [{"budget_limit": 10.0, "time_period": "1d"}, {"budget_limit": 50.0, "time_period": "7d"}].
    Returns:
    - key: (str) The generated api key for the user
    - expires: (datetime) Datetime object for when key expires.
    - user_id: (str) Unique user id - used for tracking spend across multiple keys for same user id.
    - max_budget: (float|None) Max budget for given user.

    Usage Example 

    ```shell
     curl -X POST "http://localhost:4000/user/new"      -H "Content-Type: application/json"      -H "Authorization: Bearer sk-1234"      -d '{
         "username": "new_user",
         "email": "new_user@example.com"
     }'
    ```
    r   )Ú_license_checkrB   NrÆ   r”   éô  )Útotal_usersé“  zOLicense is over limit. Please contact support@berri.ai to upgrade your license.zyOnly proxy admins can create administrative users (proxy_admin, proxy_admin_viewer). Attempted to create user with role: z. Your role: rÅ   )rm   rB   r¨   Úrequest_typerq   rÀ   ro   )ro   rÀ   r©   r    rÁ   r{   )ro   r    r©   rv   rB   )ro   r¨   rB   r©   ÚtokenÚtoken_idÚ r…   )r_   rk   r©   z!/user/new: Exception occured - %s© )2Úlitellm.proxy.proxy_serverrã   rB   r   ÚCommonProxyErrorsÚdb_not_connected_errorr~   r"   ru   r§   ro   r¤   r    r2   Úcount_billable_usersÚis_over_limitr{   r|   r}   ÚPROXY_ADMIN_VIEW_ONLYrf   ÚUserAPIKeyAuthr$   Újsonr†   r'   rc   rv   rÛ   r   r€   rw   rh   r%   ri   rÏ   rÞ   r¿   r   ÚNewUserResponseÚmodel_fieldsÚmodel_validater¼   Úcreate_taskr   Úasync_user_created_hookr—   r   Ú	exceptionr*   )r_   r©   rã   rB   Úbillable_usersrm   rv   Úorganization_idsrk   Ú_team_idro   Úspecial_keysÚresponse_dictr…   r~   Únew_user_responserÎ   s                    rI   Únew_userr   «  sÍ  è ø€ ðVs+ßLàÐ Ü¨CÔ8I×8`Ñ8`×8fÑ8fÔgÐgàÐ ÜØÜ(×?Ñ?×EÑEôð ô 	! ×!5Ñ!5Ô6ô ' t§|¡|°]ÓC×CÐCÜ)¨$¯/©/¸=ÓI×IÐIô '5°]Ó&C×&XÑ&XÓ&Z× ZˆÙ˜n×:Ñ:À~Ð:ÔVÜØØhôð ð �N‰NÔ/×;Ñ;Ô=M×=cÑ=cÐdÑdÜÐ,¬nÔ=Ø!×+Ñ+Ô/?×/KÑ/KÒKäØð Sð  TX÷  Tbñ  Tbð  Scð  cpð  qB÷  qLñ  qLð  pMð  Nôð ô
 	-ØØ/õ	
ð
 —I‘I“Kˆ	Ü4°YÀÓEˆ	ô 1¸9ÐTaÔb×bˆ	Ü˜yÔ)Ø—
‘
ˆØˆ=Ü-Ó/ˆEÜ"&¤t¬C¡y°4Ñ'7¸¿¹ÀÐX\Ó9]Ó"^Ðä 6Ñ XÀFÐ XÈiÑ X×Xˆð $Ÿ-™-¨	°4Ó8ˆØÐÜ#ÜœS (§,¡,¨yÓ"9Ó:Ø Ø"3ØŸ?™?Ø#'Ø ô÷ ñ ð ÐÜ.ÜœS (§,¡,¨yÓ"9Ó:ØŸ?™?Ø"3ØØ+ô÷ ð ô œc D™j¨(¯,©,°yÀ$Ó*GÓHˆàÐ'¨GÐ,?Ü,ØØ.Ø+Ø"3ô	÷ ð ð  '¨
Ð3ˆØ!ˆØ"Ÿ.™.Ó*ò 	+‰JˆC�Ø”o×2Ñ2Ò2°sÀ,Ò7NØ%*�˜cÒ"ð	+ð  (Ÿ|™|¨G°RÓ8ˆ�eÑä#2×#AÑ#AÀ-Ó#PÐô
 	×ÑÜ$×<Ñ<ØØ*Ø"3ôô	
ð !Ð ðE 	DùØIùð ![ùð< cùð Yùðùðøðùô@ ò +Ü×&Ñ&Ð'JÈAÔNÜ'¨Ó*Ð*ûð+üsÊ   ‚N;„BN	 ÂM3Â	N	 Â&M6Â' N	 ÃM9ÃCN	 Æ&M<Æ'A!N	 ÈM?È	AN	 ÉNÉAN	 ÊNÊ=N	 ËNË2N	 ÌN	 ÌAN	 Í2N;Í3N	 Í6N	 Í9N	 Í<N	 Í?N	 ÎN	 ÎN	 ÎN	 Î		N8Î!N3Î3N8Î8N;z/user/available_roles)rß   Úinclude_in_schemarà   c              ƒ   óö   K  — i }t         D ]i  }|t         j                  t         j                  t         j                  t         j                  fv sŒD|j
                  |j                  dœ||j                  <   Œk |S ­w)zÕ
    Endpoint used by Admin UI to show all available roles to assign a user
    return {
        "proxy_admin": {
            "description": "Proxy Admin role",
            "ui_label": "Admin"
        }
    }
    )ÚdescriptionÚui_label)r|   r}   rñ   r‚   ÚINTERNAL_USER_VIEW_ONLYr  r  r~   )r©   Ú_data_to_returnr¬   s      rI   Úui_get_available_roler  l  sw   è ø€ ð&  €OÜ ò ˆàÜ×(Ñ(Ü×2Ñ2Ü×*Ñ*Ü×4Ñ4ð	
ò 
ð  $×/Ñ/Ø ŸM™Mñ+ˆO˜DŸJ™JÒ'ðð Ðùs   ‚AA9Á*A9Ú	team_listc                 ó>   — | €y | D ]  }|j                   |k(  sŒ|c S  y rF   )rÀ   )r  rÀ   rÕ   s      rI   Úget_team_from_listr
  �  s2   € ð ÐØàò ˆØ�<‰<˜7Ó"ØŠKðð rL   c                 óT   — d}t        | «      |kD  ry| D ]  }t        |«      dk  sŒ y y)z:Validate that a decoded user_id is safe to use downstream.i   Fé    T)r�   Úord)ro   ÚMAX_USER_ID_LENGTHÚchs      rI   Ú_is_valid_user_idr  œ  s:   € à #ÐÜ
ˆ7ƒ|Ð(Ò(Øàò ˆÜˆr‹7�T‹>Ùðð rL   Úrequestc                 óÔ   — d}t        | j                  j                  «      }d|v rBddl}ddlm} |j                  d|«      }|r$ ||j                  d«      «      }t        |«      r|}|S )z*
    Get the user id from the request
    Nzuser_id=r   )Úunquotezuser_id=([^&]*)é   )	rw   ÚurlÚqueryÚreÚurllib.parser  ÚsearchÚgroupr  )r  ro   Úquery_stringr  r  ÚmatchÚraw_user_ids          rI   Úget_user_id_from_requestr  ¨  sc   € ð
 €GÜ˜gŸk™k×/Ñ/Ó0€LØ�\Ñ!ãÝ(à—y‘yÐ!3°\ÓBˆÙá!(¨¯©°Q«Ó!8ˆKÜ  Ô-Ø%�Ø€NrL   c                 ó*   — |�d|v rt        | ¬«      S |S )z>Normalize URL-decoded user_id while preserving '+' characters.r“   ©r  )r  ©r  ro   s     rI   Ú_normalize_user_info_user_idr"  ½  s   € àÐ˜s g™~Ü'°Ô8Ð8Ø€NrL   c                 ó–   — | €yt        |«      ry| |j                  k(  ryt        t        j                  d| › d|j                  › �¬«      ‚)aÛ  Re-validate that the caller may read the resolved ``user_id`` after
    URL-decoding has been finalized.

    The route-level check in ``RouteChecks.non_proxy_admin_allowed_routes_check``
    runs against ``request.query_params``, which decodes a literal ``+`` to a
    space. ``_normalize_user_info_user_id`` then re-parses the raw query with
    ``unquote`` so the endpoint can return rows for user_ids that contain ``+``
    (e.g. plus-addressed emails). That asymmetry let an attacker who registered
    a username with a literal space pass the route check and then read another
    user's row by sending the encoded ``+`` form. Re-checking ownership here
    closes the gap without changing the supported user_id grammar.
    Nz4key not allowed to access this user's info. user_id=z, key's user_id=r”   )r    ro   r   r   ÚHTTP_403_FORBIDDEN©ro   r©   s     rI   Ú_enforce_user_info_accessr&  Ä  s[   € ð €Øô Ð-Ô.ØØÐ#×+Ñ+Ò+ØÜ
Ü×-Ñ-àBÀ7À)ÐK[Ð\m×\uÑ\uÐ[vÐwôð rL   Ú	user_infoc              ƒ   óº  K  — ddl m} g }g } |t        dddœ¬«      ||¬«      ƒ d{  –—† }|�+t        |t        «      r|}|D �cg c]  }|j
                  ‘Œ }}d}	t        |d	d«      }
|
r-t        |
t        «      r| j                  |
d
d¬«      ƒ d{  –—† }	n]|j                  �Q|€O| j                  |j                  ¬«      ƒ d{  –—† }t        |d	d«      }|r| j                  |d
d¬«      ƒ d{  –—† }	|	�Rt        |	t        «      rB|	D ]=  }|j
                  |vsŒ|j                  |«       |j                  |j
                  «       Œ? ||fS 7 �Œ%c c}w 7 ŒÂ7 Œ‘7 Œh­w)z9Fetch and merge teams from membership + user.teams field.r   )Ú	list_teamr¯   ú
/user/infor±   r´   )r¶   ro   r©   Nrv   rÕ   Úfind_all)Úteam_id_listrr   Ú
query_type©ro   )
rÇ   r)  r   rf   r€   rÀ   rš   Úget_dataro   r¹   )rB   ro   r'  r©   r)  r  r,  Úteams_1rÕ   Úteams_2Útarget_team_idsÚcaller_user_infoÚcaller_team_idss                rI   Ú_get_user_info_teamsr5  â  s‡  è ø€ õ Là.0€IØ €Lá$ÜØ!¨<Ñ8ô
ð Ø+ô÷ €Gð Ðœz¨'´4Ô8Øˆ	Ø18Ö9¨˜Ÿ›Ð9ˆÐ9à37€GÜ$ Y°¸Ó>€Oáœ: o´tÔ<Ø%×.Ñ.Ø(ØØ!ð /ó 
÷ 
‰ð
 
×	"Ñ	"Ð	.°7°?Ø0=×0FÑ0FÐO`×OhÑOhÐ0FÓ0i×*iÐÜ!(Ð)9¸7ÀDÓ!IˆÙØ)×2Ñ2Ø,Ø!Ø%ð 3ó ÷ ˆGð Ðœz¨'´4Ô8Øò 	2ˆDØ�|‰| <Ò/Ø× Ñ  Ô&Ø×#Ñ# D§L¡LÕ1ð	2ð
 �gÐÐðKûò :ð
øð +jøðúsW   ‚&E¨E©EÁEÁ:EÂEÂ2EÃEÃ*EÃ0EÃ1)EÄ3EÅEÅEÅEÚ_SCIM_DIRECTORY_METADATA_KEYSÚmetadatac                 ó¶   — t        | t        «      rt        j                  | «      s| S | j	                  «       D ��ci c]  \  }}|t        vsŒ||“Œ c}}S c c}}w )a  SCIM enterprise attributes, entitlements, and roles are persisted in user
    metadata so reporting can group on them, but they are directory-only fields
    that generic user-info endpoints must not surface; SCIM clients read them
    through the SCIM endpoints.)rf   rg   r6  Úintersectionr   )r7  ÚkÚvs      rI   Ú _redact_scim_enterprise_metadatar<    sM   € ô �h¤Ô%Ô-J×-WÑ-WÐX`Ô-aØˆØ%Ÿ^™^Ó-×X‘T�Q˜°Ô:WÒ1WˆAˆq‰DÓXÐXùÓXs   »AÁAÚkeysr0  Úmodel_max_budget_usagec                 ód  — |€|�t        d„ |D «       «      }d|i}t        ||¬«      }|j                  d„ ¬«       t        |t        «      r|j                  «       n|}t        |t        «      r6|j                  dd«       t        |j                  d«      «      |d<   |�||d	<   t        | |||¬
«      S )z9Create UserInfoResponse while filtering sensitive fields.Nc              3   ó6   K  — | ]  }t        |d d«      –— Œ y­w)Úspendr   N©rš   )rÔ   r:  s     rI   rÖ   z,_build_user_info_response.<locals>.<genexpr>1  s   è ø€ Ò@°aœ7 1 g¨q×1Ñ@ùs   ‚rA  ©r=  Ú	all_teamsc                 ó$   — t        | dd«      xs dS ©NÚ
team_aliasrê   rB  ©Úxs    rI   ú<lambda>z+_build_user_info_response.<locals>.<lambda>5  s   € ¤¨¨L¸"Ó!=Ò!CÀ€ rL   ©r…   ra   r7  r>  ©ro   r'  r=  rv   )ÚsumÚ_process_keys_for_user_infoÚsortrf   Ú	BaseModelÚ
model_dumprg   rh   r<  ri   ÚUserInfoResponse)	ro   r'  r=  r  r0  r>  rA  Úreturned_keysÚ
_user_infos	            rI   Ú_build_user_info_responserU  '  s¹   € ð Ð˜TÐ-ÜÑ@¸4Ô@Ó@ˆØ˜eÐ$ˆ	ä6¸DÈGÔT€MØ‡N�NÑC€NÔDä2<¸YÌ	Ô2R˜	×,Ñ,Ô.ÐXa€JÜ�*œdÔ#Ø�‰�z 4Ô(Ü!AÀ*Ç.Á.ÐQ[ÓB\Ó!]ˆ
�:ÑØ!Ð-Ø3IˆJÐ/Ñ0äØØØØô	ð rL   r*  z!User ID in the request parameters)Údefaultr  c              ƒ   ó¤  K  — ddl m}m} 	 t        | |¬«      }t	        ||¬«       |€t        d«      ‚|€t        |«      rt        |¬«      ƒ d{  –—† S |€|j                  }d}|�|j                  |¬«      ƒ d{  –—† }|€t        d	d
|› d�¬«      ‚t        ||||¬«      ƒ d{  –—† \  }}|j                  |dd¬«      ƒ d{  –—† }t        |||||t        t        j                  |t!        |dd«      |j"                  ¬«      ƒ d{  –—† ¬«      }	|	S 7 ŒÄ7 Œš7 Œr7 ŒU7 Œ# t
        $ r&}
t%        j&                  d|
«       t)        |
«      ‚d}
~
ww xY w­w)aA  
    [10/07/2024]
    Note: To get all users (+pagination), use `/user/list` endpoint.


    Use this to get user information. (user row + all user key info)

    Example request
    ```
    curl -X GET 'http://localhost:4000/user/info?user_id=krrish7%40berri.ai'     --header 'Authorization: Bearer sk-1234'
    ```
    r   ©Úmodel_max_budget_limiterrB   r!  r%  Nú�Database not connected. Connect a database to your proxy - https://docs.litellm.ai/docs/simple_proxy#managing-auth---virtual-keys)r©   r.  é”  úUser z
 not foundr”   )rB   ro   r'  r©   r…   r+  )ro   rr   r-  Úmodel_max_budget©Úentity_typeÚ	entity_idr]  Úcache)ro   r'  r=  r  r0  r>  z>litellm.proxy.proxy_server.user_info(): Exception occured - %s)rì   rY  rB   r"  r&  r—   r    Ú_get_user_info_for_proxy_adminro   r/  r   r5  rU  r   ÚLitellm_EntityTypeÚUSERrš   Ú
dual_cacher   rù   r*   )r  ro   r©   rY  rB   r'  r  r0  r=  Úresponse_datarÎ   s              rI   r'  r'  F  sœ  è ø€ ÷2 Sð7+Ü.°wÈÔPˆÜ!¨'ÐEVÕWàÐ Üð Tóð ð ˆ?Ô3Ð4EÔFÜ7ÐJ[Ô\×\Ð\Øˆ_Ø'×/Ñ/ˆGð ˆ	ØÐØ+×4Ñ4¸WÐ4ÓE×EˆIàÐÜØØ˜w˜i zÐ2ôð ô
 $8Ø'ØØØ/ô	$
÷ 
Ñˆ	�7ð *×2Ñ2ØØØ!ð 3ó 
÷ 
ˆô  9ØØØØØÜ)EÜ.×3Ñ3Ø!Ü!(¨Ð4FÈÓ!MØ.×9Ñ9ô	*÷ $ô 
ˆð ÐðW ]øð Føð
øð
øð$ùô ò +Ü×&Ñ&Ð'gÐijÔkÜ'¨Ó*Ð*ûð+üs�   ‚	EŒAD ÁDÁD ÁEÁ'D Á;DÁ<)D Â%DÂ&D ÃDÃAD ÄDÄ	
D ÄEÄD ÄD ÄD ÄD ÄD Ä	EÄ'!EÅEÅEÚtarget_user_idz&prisma_models.LiteLLM_UserTable | Nonec              ƒ   ó|  ‡‡K  — ddl mŠ ‰€yˆˆfd„}t        | «      r |«       ƒ d{  –—† S | j                  ‰k(  r |«       ƒ d{  –—† S | j                  �Øt	        ‰«      j                  d| j                  i¬«      ƒ d{  –—† }|�§|j                  r› |«       ƒ d{  –—† }|€yt        ‰«      j                  dd|j                  ii¬«      ƒ d{  –—† }|D ]S  }t        j                  |j                  «       «      }t        | |¬	«      sŒ4|j                  |j                  xs g v sŒQ|c S  y7 �Œ7 Œì7 Œ³7 Œ˜7 Œf­w)
a×  
    Check if the caller is allowed to access the target user's info.

    Returns the target user's DB row if access is allowed, None otherwise.
    Returning the row avoids a redundant DB fetch in the caller.

    Access rules:
    1. Proxy admins / proxy admin viewers can access any user
    2. User can access their own info
    3. Team admins can access info of users in their teams

    Raises on unexpected DB errors so they surface as 500s, not silent 404s.
    r   ©rB   Nc               “   ó`   •K  — t        ‰ «      j                  d‰iddi¬«      ƒ d {  –—† S 7 Œ­w)Nro   Úobject_permissionT)r‘   Úinclude)rJ   Úfind_unique)rB   rg  s   €€rI   Ú_fetch_target_userz6_check_user_info_v2_access.<locals>._fetch_target_user³  s>   øè ø€ Ü  Ó/×;Ñ;Ø˜nÐ-Ð8KÈTÐ7Rð <ó 
÷ 
ð 	
ð 
ús   ƒ$.§,¨.ro   r�   rÀ   Úin)r©   Úteam_obj)rì   rB   r    ro   rJ   rm  rv   rO   Ú	find_manyÚLiteLLM_TeamTablerö   rQ  r   rÀ   )	r©   rg  rn  Úcaller_userÚtarget_userrv   rÕ   rp  rB   s	    `      @rI   Ú_check_user_info_v2_accessru  ›  sG  ùè ø€ õ" 9àÐØõ
ô Ð-Ô.Ù'Ó)×)Ð)ð × Ñ  NÒ2Ù'Ó)×)Ð)ð × Ñ Ð,ä#.¨}Ó#=×#IÑ#IÐQZÐ\m×\uÑ\uÐPvÐ#IÓ#w×wˆØÐ" {×'8Ò'8á'9Ó';×!;ˆKØÐ"Øô "-¨]Ó!;×!EÑ!EÈYÐY]Ð_j×_pÑ_pÐXqÐLrÐ!EÓ!s×sˆEØò +�Ü,×;Ñ;¸D¿O¹OÓ<MÓN�Ü&Ð9JÐU]Ö^à—|‘|¨×(9Ñ(9Ò(?¸RÒ@Ø*Ò*ð+ð ð3 *ùð *øð
 xøð "<øð
 túsc   „%D<©D1ªD<ÁD4Á:D<ÂD6ÂD<ÂD8Â 3D<ÃD:Ã9D<ÄD<Ä+D<Ä4D<Ä6D<Ä8D<Ä:D<z/v2/user/infoc              ƒ   óº  K  — ddl m}m} 	 |€%t        dt        j
                  j                  ¬«      ‚|�d|v rt        | ¬«      }|€|j                  }|€t        dd	¬«      ‚t        ||¬
«      ƒ d{  –—† }|€t        dd|› �¬«      ‚|j                  «       }t        d!i d|j                  d|«      “d|j                  d«      “d|j                  d«      “d|j                  d«      “d|j                  dd«      “d|j                  d«      “d|j                  d«      xs g “d|j                  d«      “d|j                  d«      “dt        |j                  d«      «      “d|j                  d«      “d|j                  d«      “d|j                  d«      “d|j                  d«      xs g “d|j                  d«      “d|j                  d«      “dt        t        j                   |j                  d|«      |j                  d«      |j"                  ¬«      ƒ d{  –—† “ŽS 7 �Œ²7 Œ	# t$        $ r&}t'        j(                  d |«       t+        |«      ‚d}~ww xY w­w)"uŸ  
    Lightweight endpoint to get user info. Returns only the user object â€” no keys, no teams objects.

    This is the v2 replacement for /user/info, designed to avoid the "god endpoint" problem
    where the old endpoint loaded all keys and teams into memory.

    Access control:
    - Proxy admins can query any user
    - Team admins can query users within their teams
    - Internal users can only query themselves (omit user_id or pass own)
    - Returns 404 for non-existent users or unauthorized access

    Example request:
    ```
    curl -X GET 'http://localhost:4000/v2/user/info?user_id=user123' \
    --header 'Authorization: Bearer sk-1234'
    ```
    r   rX  Nrä   r”   r“   r   rÆ   z_user_id is required. Either pass it as a query parameter or authenticate with a user-bound key.)r©   rg  r[  zUser not found: ro   r    Ú
user_aliasr{   rA  g        rt   r<   ru   Úbudget_reset_atr7  Ú
created_atÚ
updated_atÚsso_user_idrv   rk  r]  r>  r^  zAlitellm.proxy.proxy_server.user_info_v2(): Exception occured - %srë   )rì   rY  rB   r   rí   rî   r~   r  ro   ru  rQ  ÚUserInfoV2Responseri   r<  r   rc  rd  re  r—   r   rù   r*   )r  ro   r©   rY  rB   Úuser_rowÚ	user_datarÎ   s           rI   Úuser_info_v2r  Ö  s“  è ø€ ÷< Sð?+ØÐ ÜØÜ(×?Ñ?×EÑEôð ð Ð 3¨'¡>Ü.°wÔ?ˆGð ˆ?Ø'×/Ñ/ˆGàˆ?ÜØØxôð ô !;Ø/Ø"ô!
÷ 
ˆð
 ÐÜØØ)¨'¨Ð3ôð ð
 $×.Ñ.Ó0ˆ	ä!ò 
Ø—M‘M )¨WÔ5ð
à —}‘} \Ô2ð
ð !—}‘} \Ô2ð
ð  —m‘m KÔ0ð	
ð
 —-‘- ¨Ô-ð
ð !—}‘} \Ô2ð
ð —=‘= Ó*Ò0¨bøð
ð &ŸM™MÐ*;Ô<ð
ð &ŸM™MÐ*;Ô<ð
ô 6°i·m±mÀJÓ6OÔPð
ð !—}‘} \Ô2ð
ð !—}‘} \Ô2ð
ð "Ÿ™ mÔ4ð
ð —-‘- Ó(Ò.¨Bøð
ð (Ÿm™mÐ,?Ô@ð
ð  'Ÿ]™]Ð+=Ô>ð!
ô" *FÜ.×3Ñ3Ø#Ÿ-™-¨	°7Ó;Ø!*§¡Ð/AÓ!BØ.×9Ñ9ô	*÷ $ð $ð#
ð 	
ð
ùð<$ùô ò +Ü×&Ñ&Ð'jÐlmÔnÜ'¨Ó*Ð*ûð+üsN   ‚	IŒA&H) Á2H$Á3F*H) ÈH'ÈH) È#IÈ$H) È'H) È)	IÈ2!IÉIÉIc              ƒ   óò  K  — ddl m} d}|€t        d«      ‚|j                  j	                  |«      ƒ d{  –—† }t        j                  d|«       |d   d   xs g }g }|D ]<  }|j                  d«      €g |d<   |j                  t        j                  |«      «       Œ> |d   d	   xs g }|D �cg c]  }t        j                  |«      ‘Œ }}|j                  d
„ ¬«       t        ||¬«      }	| j                  }
d}|
�`|j                  |
¬«      ƒ d{  –—† }|�Dt!        |t"        «      r|j%                  «       n|}t!        |t&        «      r|j)                  dd«       t+        |
||	|¬«      S 7 �Œ7c c}w 7 Œa­w)a1  
    Admin UI Endpoint - Returns All Teams and Keys when Proxy Admin is querying

    - get all teams in LiteLLM_TeamTable
    - get all keys in LiteLLM_VerificationToken table

    Why separate helper for proxy admin ?
        - To get Faster UI load times, get all teams and virtual keys in 1 query
    r   ri  zç
        SELECT 
            (SELECT json_agg(t.*) FROM "LiteLLM_TeamTable" t) as teams,
            (SELECT json_agg(k.*) FROM "LiteLLM_VerificationToken" k WHERE k.team_id != 'litellm-dashboard' OR k.team_id IS NULL) as keys
    NrZ  zresults_keys: %sr=  r<   rv   c                 ó$   — t        | dd«      xs dS rF  rB  rH  s    rI   rJ  z0_get_user_info_for_proxy_admin.<locals>.<lambda>^  s   € ¤G¨A¨|¸RÓ$@Ò$FÀB€ rL   rK  rC  r.  ra   rL  )rì   rB   r—   ÚdbÚ	query_rawr   rÊ   ri   r¹   ÚLiteLLM_VerificationTokenrö   rr  rO  rN  ro   r/  rf   rP  rQ  rg   rh   rR  )r©   rB   Ú	sql_queryÚresultsÚ_keys_in_dbÚ
keys_in_dbr…   Ú_teams_in_dbrÕ   rS  Úadmin_user_idÚadmin_user_infos               rI   rb  rb  8  sŸ  è ø€ õ 9ð€Ið
 ÐÜð Pó
ð 	
ð )×+Ñ+×5Ñ5°iÓ@×@€Gä×ÑÐ1°7Ô;à6=¸a±jÀÑ6HÒ6NÈB€Kà€JØò IˆØ�7‰7�8ÓÐ$ØˆC�‰MØ×ÑÔ3×BÑBÀ3ÓGÕHðIð -4°A©J°wÑ,?Ò,EÀ2€LØGSÖT¸tÔ%×4Ñ4°TÕ:ÐT€LÐTØ×ÑÑFÐÔGÜ6¸JÐR^Ô_€Mð -×4Ñ4€MØ€OàÐ Ø -× 6Ñ 6¸}Ð 6Ó M×MˆØÐ&ä0:¸?ÌIÔ0V�×*Ñ*Ô,Ð\kð ô ˜/¬4Ô0Ø×#Ñ# J°Ô5äØØ!ØØô	ð ð? Aûò Uð Nús0   ‚4E7¶E-·A9E7Â0E0ÃAE7ÄE5ÄAE7Å0E7rD  c                 ó´  — ddl m} ddlm}m} g }| €	 |S | D ]ž  }|j
                  |k(  r|j                  dd«      du rŒ'	 |j                  «       }|j                  d«      |k(  rŒMd|v r8|d   �3|d   dk7  r+t        ||d   ¬	«      }|�t        |d
d «      }	|	|d
<   nd |d
<   nd|d
<   |j                  |«       Œ  |S # t        $ r |j                  «       }Y Œ†w xY w)Nr   ©ÚUI_SESSION_TOKEN_TEAM_ID)Úgeneral_settingsÚlitellm_master_key_hashÚdisable_master_key_returnFTrÀ   zlitellm-dashboard)r  rÀ   rG  ÚNone)Úlitellm.constantsrŽ  rì   r�  r�  rè   ri   rQ  r—   rg   r
  rš   r¹   )
r=  rD  rŽ  r�  r�  rS  r…   Ú_keyÚ	team_inforG  s
             rI   rN  rN  v  s  € õ ;ßTà€MØ€|Øð< Ðð9 ò 	'ˆCà—	‘	Ð4Ò4Ø$×(Ñ(Ð)DÀeÓLØñð ð"Ø Ÿ^™^Ó-�ð �x‰x˜	Ó"Ð&>Ò>Øà˜DÑ  T¨)¡_Ð%@ÀTÈ)Á_ÐXkÒEkÜ.¸ÈDÐQZÉOÔ\�	ØÐ(Ü!(¨°LÀ$Ó!G�JØ)3�D˜Ò&à)-�D˜Ò&à%+��\Ñ"Ø× Ñ  Õ&ð7	'ð8 Ðøô% ò "à—x‘x“z’ð"ús   Á B;Â;CÃCc                 ó4  — i }t        |d«      r|j                  «       n	t        «       }| j                  «       D ]-  \  }}|dk(  rd|v sŒ|||<   Œ|€Œ|g i fvsŒ |t        vsŒ)|||<   Œ/ d}|j
                  t        j                  k(  rd}d|v r#ddlm	} t        |d   «        ||d   ¬«      |d	<   d|vr%|r#t        j                  �t        j                  |d<   d|vr:|r8t        j                  �(t        j                  |d<   ddlm	}  ||d   ¬«      |d	<   |S )
NÚ
fields_setrt   FTru   r   )Úget_budget_reset_time)ru   rx  )rj   r—  Úsetr   Ú)LiteLLM_ManagementEndpoint_MetadataFieldsr{   r|   r‚   Ú)litellm.proxy.common_utils.timezone_utilsr˜  r"   ry   rƒ   r„   )rm   r_   Únon_default_valuesr—  r:  r;  Úis_internal_userr˜  s           rI   Ú_update_internal_user_paramsrž     sR  € Ø "ÐÜ-4°T¸<Ô-H˜Ÿ™Ô)ÌcËe€Jà—‘Ó!ò &‰ˆˆ1Ø�ÒØ˜zÒ)Ø()Ð" 1Ò%à‰MØàØðòð
 ÔBÒBà$%Ð˜qÒ!ð&ð ÐØ‡~�~Ô)×7Ñ7Ò7ØÐàÐ.Ñ.ÝSä Ð!3Ð4EÑ!FÔGÙ0EØ.Ð/@ÑAô1
ÐÐ,Ñ-ð Ð-Ñ-á¤×!AÑ!AÐ!Mä/6×/OÑ/OÐ˜|Ñ,àÐ 2Ñ2Ù¤× EÑ EÐ QÜ4;×4YÑ4YÐÐ0Ñ1ÝWá4IØ 2Ð3DÑ Eô5ÐÐ0Ñ1ð ÐrL   rk   Úexisting_user_rowÚlitellm_changed_byÚlitellm_proxy_admin_namec              ƒ   ó  K  — ddl m} |€y 	 t        |«      j                  d| d   i¬«      ƒ d {  –—† }|r‘t        j                  |j                  d¬«      «      }t        j                  t        j                  |j                  d|xs |j                  |||r|j                  d¬«      nd |j                  d¬«      ¬«      «       y y 7 Œ˜# t        $ r0}t        j                  d	| j!                  d«      |«       Y d }~y d }~ww xY w­w)
Nr   ri  ro   r�   T©Úexclude_noneÚupdated©ro   Úactionr   r©   r¡  Úbefore_valueÚafter_valuez*Failed to create audit log for user %s: %s)rì   rB   rJ   r™   ÚLiteLLM_UserTablerö   rQ  r¼   r÷   r   Úcreate_internal_user_audit_logro   Úmodel_dump_jsonr—   r   Úwarningri   )	rk   rŸ  r   r©   r¡  rB   Úupdated_user_rowÚuser_row_typedÚaudit_errors	            rI   Ú_schedule_user_update_audit_logr±  Ñ  s  è ø€ õ 9àÐØðyÜ(3°MÓ(B×(MÑ(MÐU^Ð`hÐirÑ`sÐTtÐ(MÓ(u×"uÐÙÜ$5×$DÑ$DÐEU×E`ÑE`ÐnrÐE`ÓEsÓ$tˆNÜ×ÑÜ(×GÑGØ*×2Ñ2Ø$Ø'9Ò'VÐ=N×=VÑ=VØ&7Ø-EÙZkÐ"3×"CÑ"CÐQUÐ"CÔ"VÐquØ .× >Ñ >ÈDÐ >Ó Qôõ
ð ð #vùô ò yÜ×$Ñ$Ð%QÐS[×S_ÑS_Ð`iÓSjÐlw×xÑxûðyüs?   ‚
D�#C °C	±BC ÃDÃ	C Ã	DÃ&C?Ã:DÃ?DÄDÚuser_requestc                 óx  — | j                   �4|j                   t        j                  j                  k7  rt	        dd¬«      ‚|�Bt
        j                  |j                  d¬«      «      }t        ||¬«      st	        ddd	i¬«      ‚y|j                   t        j                  j                  k7  rt	        d
ddi¬«      ‚y)uJ   Authorization checks for /user/update â€” raises HTTPException on failure.Nræ   ú(Only proxy admins can modify user roles.r”   Tr£  ©r©   r'  r’   z[User does not have permission to update this user. Only PROXY_ADMIN can update other users.r[  zZUser not found. Only PROXY_ADMIN can create users via /user/update; use /user/new instead.)	r{   r|   r}   r~   r   rª  rö   rQ  Úcan_user_call_user_update)r²  r©   rŸ  Ú	typed_rows       rI   Ú_check_user_update_authzr¸  ï  sÊ   € ð ×ÑÐ)Ð.?×.IÑ.IÔM]×MiÑMi×MoÑMoÒ.oÜ¨Ð4^Ô_Ð_àÐ$Ü,×;Ñ;Ð<M×<XÑ<XÐfjÐ<XÓ<kÓlˆ	Ü(Ð;LÐXaÕbÜØàÐzðôð ð cð 
×	$Ñ	$Ô(8×(DÑ(D×(JÑ(JÒ	JäØàÐuðô
ð 	
ð 
KrL   rœ  c              ƒ   ón   K  — | j                  d«      �ddlm}  |d| d   › �¬«      ƒ d{  –—†  yy7 Œ­w)a®  Invalidate the cross-pod spend counter after a direct ``spend`` change.

    A direct ``spend`` change must also invalidate the cross-pod spend counter
    enforcement reads; the DB write alone leaves a warm counter at the stale
    value. ``non_default_values["user_id"]`` is populated in every branch of the
    caller (incl. the email-new-user insert path, whose response is a bare model
    and not safely subscriptable).
    rA  Nr   )Ú_invalidate_spend_counterzspend:user:ro   )Úcounter_key)ri   rì   rº  )rœ  rº  s     rI   Ú)_invalidate_user_spend_counter_if_changedr¼    sD   è ø€ ð ×Ñ˜gÓ&Ð2ÝHá'°kÐBTÐU^ÑB_ÐA`Ð4aÔb×bÑbð 3ð 	cús   ‚*5¬3­5c                 ó    — dt        | d«      r| j                  «       n	t        «       vry| j                  }|du xs |j	                  dd¬«       S )zêWhether the caller explicitly asked to remove this user's object_permission.

    Distinguishes "sent nothing" from "sent an empty grant set". Only the latter clears; an omitted
    field must leave an existing entitlement alone.
    rk  r—  FNT)Úexclude_unsetr¤  )rj   r—  r™  rk  rQ  )r²  Úsents     rI   Ú_clears_object_permissionrÀ    sS   € ð ÄÈÐVbÔ@c <×#:Ñ#:Ô#<ÔilÓinÑoØØ×0Ñ0€DØ�4ˆ<ÒU˜tŸ™¸TÐPT˜ÓUÐUÐUrL   Úobject_permission_ids.c              ƒ   ó  K  — ddl m} g d„ t        j                  |«      D «       ¢| �t	        | «      | fnd¢­}|D ]  }	 |j                  |¬«      ƒ d{  –—†  Œ y7 Œ# t        $ r!}t        j                  d||«       Y d}~ŒHd}~ww xY w­w)aæ  Drop the cache entries an entitlement change makes stale.

    All three kinds are needed: a permission row is cached under its own id (so re-reading the same
    link still yields the OLD grants), the ``user_id -> object_permission_id`` link is cached
    separately (so a user who previously had NO entitlement keeps its "none" sentinel), and the user
    row itself is cached whole. Leaving any behind means an admin revoking a tool keeps serving it
    until the management-object TTL expires.

    Both the outgoing and incoming permission ids are passed, because a clear leaves no incoming id
    at all and an upsert may mint a new row; invalidating only one of the two leaves the other's
    grants live.

    Each deletion is isolated: one that fails must not skip the others, or a single unreachable key
    would silently leave the rest of a revocation in place. Best-effort overall, exactly as the caches
    are everywhere else, since one we cannot clear still expires on its own.
    r   )Úuser_api_key_cachec              3   ó2   K  — | ]  }t        |«      –— Œ y ­wrF   )r   ©rÔ   Úpermission_ids     rI   rÖ   z6_invalidate_cached_user_entitlement.<locals>.<genexpr><  s   è ø€ Ò	o¸Ô
% m×
4Ñ	oùs   ‚Nrë   rK  z2Failed to invalidate cached entitlement key %r: %s)	rì   rÃ  rg   Úfromkeysr   Úasync_delete_cacher—   r   r­  )ro   rÁ  rÃ  r=  r…   rÎ   s         rI   Ú#_invalidate_cached_user_entitlementrÉ  (  s    è ø€ õ" >ðÙ	oÌ$Ï-É-ÐXmÓJnÔ	oðàELÐEXÔ.¨wÓ7¸Ñ
AÐ^`ñ€Dð ò gˆð	gØ$×7Ñ7¸CÐ7Ó@×@Ñ@ñgà@ùÜò 	gÜ ×(Ñ(Ð)]Ð_bÐde×fÑfûð	güs@   ‚<B¿AÁAÁAÁBÁAÁ	BÁ'BÁ>BÂBÂBc              ƒ   óŽ  K  — ddl m}m} |€t        d«      ‚| j                  s| j
                  st        d«      ‚t        | |¬«       | j                  d¬«      }t        || ¬	«      }t        |«       d}| j                  r0t        |«      j                  d
| j                  i¬«      ƒ d{  –—† }n;| j
                  r/t        |«      j                  d| j
                  i¬«      ƒ d{  –—† }t        | ||«       |�%t        j                  |j                  d¬«      «      }| j                  xs |�t!        |d
d«      nd}|duxr |j                  |k(  }	|	rq|j"                  t$        j&                  j(                  k7  rJt+        | d«      r| j-                  «       n	t/        «       }
d}|D ]  }||v s||
v sŒt1        ddd|› d�i¬«      ‚ |�t3        t4        t!        |di «      xs i «      ni }t7        | ||xs i ¬«      }t9        |j;                  d«      «       d|v r)t=        |t!        |dd«      |¬«      ƒ d{  –—† }|�||d<   nt?        | «      rd|d<   d}| j                  rNtA        | j                  «      dkD  r6| j                  |d
<   |jC                  | j                  |d¬«      ƒ d{  –—† }nÞ| j
                  rÒ|jE                  d| j
                  idd¬«      ƒ d{  –—† }|r\tG        |tH        «      rLtA        |«      dkD  r>|D ]8  }|j                  |d
<   |jC                  |j                  |d¬«      ƒ d{  –—† } nN nLtK        tM        jN                  «       «      |d
<   | j
                  |d<   |jQ                  |d¬«      ƒ d{  –—† }|}|�tS        |||||¬ «      ƒ d{  –—†  tU        |«      ƒ d{  –—†  d|v rPtW        |j;                  d
«      tY        d!„ t!        |dd«      |j;                  d«      fD «       «      ¬"«      ƒ d{  –—†  |€t1        d#dd$i¬«      ‚t[        |«       |S 7 �Œ�7 �ŒH7 �Œü7 �ŒŒ7 �ŒZ7 �Œ7 Œ·7 Œ�7 ŒŒ7 Œ:­w)%zµ
    Helper function to update a single user.
    Used by both user_update and bulk_user_update endpoints.

    Returns the updated user data or raises an exception on failure.
    r   ©r¡  rB   NzNot connected to DB!z-Either user_id or user_email must be providedrÅ   T©r¾  ©rm   r_   ro   r�   r    r£  r—  )rt   Úsoft_budgetrA  rk  ræ   r’   zNon-admin users cannot modify 'z0' on their own record. Contact your proxy admin.r”   r7  )r_   rœ  Úexisting_metadatarA  rk  Úobject_permission_id)rm   Úexisting_object_permission_idrB   rq   )ro   r_   rr   r+  )Úkey_valrr   r-  )r_   rr   )rk   rŸ  r   r©   r¡  c              3   ó@   K  — | ]  }t        |t        «      r|–— Œ y ­wrF   rÒ   rÅ  s     rI   rÖ   z-_update_single_user_helper.<locals>.<genexpr>Ó  s$   è ø€ ò ,à%ô " -´Ô5ô "ñ,ùs   ‚)ro   rÁ  rÆ   zFailed to update user).rì   r¡  rB   r—   ro   r    rÝ   r$   rQ  rž  rc   rJ   r™   r¸  rª  rö   rš   r{   r|   r}   r~   rj   r—  r™  r   r   rg   r&   r#   ri   r(   rÀ  r�   Úupdate_datar/  rf   r€   rw   r   rx   Úinsert_datar±  r¼  rÉ  Útuplerl   )r²  r©   r   r¡  rB   rm   rœ  rŸ  Ú_target_user_idÚ_is_self_updateÚ_sent_fieldsÚ_protected_fieldsÚ_fieldrÏ  rÐ  rk   Úexisting_user_rowsrœ   Úinserted_user_rows                      rI   Ú_update_single_user_helperrÞ  F  sè  è ø€ ÷ SàÐÜÐ.Ó/Ð/à×Ò¨×(?Ò(?ÜÐHÓIÐIä(ØØ+õð
 *×4Ñ4À4Ð4ÓH€IÜ5À	ÐP\Ô]ÐÜÐ-Ô.à*.ÐØ×ÒÜ"-¨mÓ"<×"GÑ"GÈyÐZf×ZnÑZnÐNoÐ"GÓ"p×pÑØ	×	 Ò	 Ü"-¨mÓ"<×"GÑ"GÈ|Ð]i×]tÑ]tÐNuÐ"GÓ"v×vÐä˜\Ð+<Ð>OÔPàÐ$Ü-×<Ñ<Ð=N×=YÑ=YÐgkÐ=YÓ=lÓmÐð *×1Ñ1ò Ø7HÐ7TŒÐ! 9¨dÔ3ÐZ^ð ð -°DÐ8ÒiÐ=N×=VÑ=VÐZiÑ=i€OÙÐ,×6Ñ6Ô:J×:VÑ:V×:\Ñ:\Ò\ô <CÀ<ÐQ]Ô;^˜l×5Ñ5Ô7ÔdgÓdiˆØ#^ÐØ'ò 	ˆFØÐ+Ñ+¨v¸Ò/EÜ#Ø #àÐ#BÀ6À(ÐJzÐ!{ðôð ð	ð IZÐHeŒŒT”7Ð,¨j¸"Ó=ÒCÀÔDÐkmð ô 1ØØ-Ø+Ò1¨rôÐô Ð,×0Ñ0°Ó9Ô:ð Ð0Ñ0Ü,RØ(Ü*1Ð2CÐE[Ð]aÓ*bØ'ô-
÷ '
Ðð
  Ð+Ø9MÐÐ5Ò6Ü	" <Ô	0ð 6:ÐÐ1Ñ2ð '+€Hà×Ò¤ L×$8Ñ$8Ó 9¸AÒ =Ø(4×(<Ñ(<Ð˜9Ñ%Ø&×2Ñ2Ø ×(Ñ(Ø#Øð 3ó 
÷ 
‰ð
 
×	 Ò	 à*7×*@Ñ*@Ø! <×#:Ñ#:Ð;ØØ!ð +Aó +
÷ %
Ðñ ¤*Ð-?ÄÔ"FÌ3ÐOaÓKbÐefÒKfØ!3ò �Ø0=×0EÑ0EÐ" 9Ñ-Ø!.×!:Ñ!:Ø)×1Ñ1Ø+Ø%ð ";ó "÷ �ñ
 ñô -0´·
±
³Ó,=Ð˜yÑ)Ø/;×/FÑ/FÐ˜|Ñ,Ø-:×-FÑ-FÐL^ÐkqÐ-FÓ-r×'rÐØ(ˆHàÐÜ-ØØ/Ø1Ø/Ø%=ô
÷ 	
ð 	
ô 8Ð8JÓK×KÐKà!Ð%7Ñ7Ü5Ø*×.Ñ.¨yÓ9Ü&+ñ ,ô  Ð 1Ð3IÈ4ÓPØ*×.Ñ.Ð/EÓFð*ô,ó 'ô
÷ 
ð 
ð ÐÜØØÐ4Ð5ô
ð 	
ô " (Ô+Ø€Oð qùàvùð`'
ùð$
ùð%
ùðùð (søð	
øð 	Løð
úsÀ   ‚B(QÂ*P+Â+;QÃ&P.Ã'C
QÆ2BQÈ5P1È6A2QÊ(P4Ê)4QËP7ËAQÌ7P:Ì8AQÎP=ÎQÎ!P?Î"QÎ4QÎ5AQÐQÐ	#QÐ.QÐ1QÐ4QÐ7QÐ:QÐ=QÐ?QÑQÑQc                 ó†   — | j                   t        j                  j                  k(  s| j                  |j                  k(  ryy)zB
    Helper to check if the user has access to the key's info
    TF)r{   r|   r}   r~   ro   rµ  s     rI   r¶  r¶  æ  s9   € ð 	×#Ñ#Ô'7×'CÑ'C×'IÑ'IÒIØ×$Ñ$¨	×(9Ñ(9Ò9àØrL   z/user/update)rß   rà   c              ƒ   ón  K  — 	 t        j                  d| «       t        | |¬«      ƒ d{  –—† }|S 7 Œ# t        $ rö}t        j                  d|«       t        j                  t        j                  «       «       t        |t        «      rPt        t        |dd|› d�«      t        j                  t        |dd	«      t        |d
t        j                  «      ¬«      ‚t        |t        «      r|‚t        dt        |«      z   t        j                  t        |dd	«      t        j                  ¬«      ‚d}~ww xY w­w)ai  
    Example curl 

    ```
    curl --location 'http://0.0.0.0:4000/user/update'     --header 'Authorization: Bearer sk-1234'     --header 'Content-Type: application/json'     --data '{
        "user_id": "test-litellm-user-4",
        "user_role": "proxy_admin_viewer"
    }'
    ```
    
    Parameters:
        - user_id: Optional[str] - Specify a user id. If not set, a unique id will be generated.
        - user_email: Optional[str] - Specify a user email.
        - password: Optional[str] - Specify a user password.
        - user_alias: Optional[str] - A descriptive name for you to know who this user id refers to.
        - teams: Optional[list] - specify a list of team id's a user belongs to.
        - send_invite_email: Optional[bool] - Specify if an invite email should be sent.
        - user_role: Optional[str] - Specify a user role - "proxy_admin", "proxy_admin_viewer", "internal_user", "internal_user_viewer", "team", "customer". Info about each role here: `https://github.com/BerriAI/litellm/litellm/proxy/_types.py#L20`
        - max_budget: Optional[float] - Specify max budget for a given user.
        - budget_duration: Optional[str] - Budget is reset at the end of specified duration. If not set, budget is never reset. You can set duration as seconds ("30s"), minutes ("30m"), hours ("30h"), days ("30d"), months ("1mo").
        - models: Optional[list] - Model_name's a user is allowed to call. (if empty, key is allowed to call all models)
        - tpm_limit: Optional[int] - Specify tpm limit for a given user (Tokens per minute)
        - rpm_limit: Optional[int] - Specify rpm limit for a given user (Requests per minute)
        - auto_create_key: bool - Default=True. Flag used for returning a key as part of the /user/new response
        - aliases: Optional[dict] - Model aliases for the user - [Docs](https://litellm.vercel.app/docs/proxy/virtual_keys#model-aliases)
        - config: Optional[dict] - [DEPRECATED PARAM] User-specific config.
        - allowed_cache_controls: Optional[list] - List of allowed cache control values. Example - ["no-cache", "no-store"]. See all values - https://docs.litellm.ai/docs/proxy/caching#turn-on--off-caching-per-request-
        - blocked: Optional[bool] - [Not Implemented Yet] Whether the user is blocked.
        - guardrails: Optional[List[str]] - [Not Implemented Yet] List of active guardrails for the user
        - policies: Optional[List[str]] - List of policy names to apply to the user. Policies define guardrails, conditions, and inheritance rules.
        - permissions: Optional[dict] - [Not Implemented Yet] User-specific permissions, eg. turning off pii masking.
        - metadata: Optional[dict] - Metadata for user, store information for user. Example metadata = {"team": "core-infra", "app": "app2", "email": "ishaan@berri.ai" }
        - max_parallel_requests: Optional[int] - Rate limit a user based on the number of parallel requests. Raises 429 error, if user's parallel requests > x.
        - soft_budget: Optional[float] - Get alerts when user crosses given budget, doesn't block requests.
        - model_max_budget: Optional[dict] - Model-specific max budget for user. [Docs](https://docs.litellm.ai/docs/proxy/users#add-model-specific-budgets-to-keys)
        - budget_fallbacks: Optional[Dict[str, List[str]]] - Per-model fallback chain tried in order when that model's own `model_max_budget` is exceeded, e.g. {"gpt-4o": ["gpt-4o-mini"]}.
        - model_rpm_limit: Optional[float] - Model-specific rpm limit for user. [Docs](https://docs.litellm.ai/docs/proxy/users#add-model-specific-limits-to-keys)
        - mcp_rpm_limit: Optional[dict] - Per-MCP-server rpm limit, keyed by MCP server name {"github": 100, "slack": 200}. Enforced for keys and teams only; values set on a user are stored but not enforced per user.
        - tag_rpm_limit: Optional[dict] - Per-request-tag rpm limit, keyed by request tag {"cell-1": 1000, "cell-2": 500}. Enforced for keys only; values set on a user are stored but not enforced per user.
        - model_tpm_limit: Optional[float] - Model-specific tpm limit for user. [Docs](https://docs.litellm.ai/docs/proxy/users#add-model-specific-limits-to-keys)
        - spend: Optional[float] - Amount spent by user. Default is 0. Will be updated by proxy whenever user is used. You can set duration as seconds ("30s"), minutes ("30m"), hours ("30h"), days ("30d"), months ("1mo").
        - agent_id: Optional[str] - The agent id associated with the user.
        - team_id: Optional[str] - [DEPRECATED PARAM] The team id of the user. Default is None.
        - duration: Optional[str] - [NOT IMPLEMENTED].
        - key_alias: Optional[str] - [NOT IMPLEMENTED].
        - object_permission: Optional[LiteLLM_ObjectPermissionBase] - internal user-specific object permission. Example - {"vector_stores": ["vector_store_1"], "mcp_servers": ["github"], "mcp_tool_permissions": {"github": ["list_issues"]}}. The MCP grants act as a ceiling on every key this user holds. IF null or {} then no object permission.
        - prompts: Optional[List[str]] - List of allowed prompts for the user. If specified, the user will only be able to use these specific prompts.
        - budget_limits: Optional[list] - List of concurrent budget windows for the user. Each window specifies a budget_limit, time_period, and optional budget_duration. Example - [{"budget_limit": 10.0, "time_period": "1d"}, {"budget_limit": 50.0, "time_period": "7d"}].

    z /user/update: Received data = %s)r²  r©   Nz@litellm.proxy.proxy_server.user_update(): Exception occured - %sr–   zAuthentication Error(ú)Úparamr’  r•   )Úmessager²   râ  ÚcodezAuthentication Error, )r   rÊ   rÞ  r—   rù   Ú	tracebackÚ
format_excrf   r   rË   rš   rÌ   Ú
auth_errorr   ÚHTTP_400_BAD_REQUESTrw   )r_   r©   rk   rÎ   s       rI   Úuser_updateré  õ  s  è ø€ ð~
Ü×"Ñ"Ð#EÀtÔLä :ØØ/ô!
÷ 
ˆð ˆð	
ùô
 ò 
Ü×&Ñ&Ð'iÐklÔmÜ×"Ñ"¤9×#7Ñ#7Ó#9Ô:Ü�aœÔ'Ü Ü  8Ð/DÀQÀCÀqÐ-IÓJÜ$×/Ñ/Ü˜a ¨&Ó1Ü˜Q ¬v×/JÑ/JÓKô	ð ô ˜œ>Ô*ØˆGÜØ,¬s°1«vÑ5Ü ×+Ñ+Ü˜!˜W fÓ-Ü×,Ñ,ô	
ð 	
ûð
üs1   ‚D5„&3 ª1«3 °D5±3 ³	D2¼C1D-Ä-D2Ä2D5Úusers_to_updatec           
   ƒ   ó  K  — g }d}d}	 | D ]c  }	 t        |||¬«      ƒ d {  –—† }|j                  t        |r|j                  d«      n|j                  |j
                  d|¬«      «       |dz  }Œe t        |t        | «      ||¬
«      S 7 Œh# t        $ r«}t        j                  d|j                  xs |j
                  |«       t        |«      }	t        j                  d|j                  xs |j
                  |	«       |j                  t        |j                  |j
                  d|	¬	«      «       |dz  }Y d }~�Œ/d }~ww xY w# t        $ r3}t        j                  d|«       t        ddt        |«      i¬«      ‚d }~ww xY w­w)Nr   )r²  r©   r   ro   T©ro   r    ÚsuccessÚupdated_userr  zFailed to update user %s: %sF)ro   r    rí  r’   ©r†  Útotal_requestedÚsuccessful_updatesÚfailed_updateszFailed to update users: %srä   r’   r”   )rÞ  r¹   r8   ri   ro   r    r—   r   rù   rw   r’   r6   r�   r   )
rê  r©   r   r†  rñ  rò  r²  rk   rÎ   Úerror_messages
             rI   Úbulk_update_processed_usersrô  P  s—  è ø€ ð
 .0€GØÐØ€Nð.GØ+ò #	$ˆLð"$Ü!;Ø!-Ø&7Ø'9ô"÷ �ð —‘Ü$Ù<D §¡¨iÔ!8È,×J^ÑJ^Ø#/×#:Ñ#:Ø $Ø%-ô	ôð # aÑ'Ñ"ð!#	$ôJ &ØÜ Ó0Ø1Ø)ô	
ð 	
ðGùô ò $Ü$×.Ñ.Ø2°L×4HÑ4HÒ4cÈL×LcÑLcÐefôô !$ A£�Ü$×*Ñ*Ø2°L×4HÑ4HÒ4cÈL×LcÑLcÐerôð —‘Ü$Ø ,× 4Ñ 4Ø#/×#:Ñ#:Ø %Ø+ô	ôð  !Ñ#–ûð%$ûô4 ò GÜ×&Ñ&Ð'CÀQÔGÜ¨°W¼cÀ!»fÐ4EÔFÐFûðGüsc   ‚FŠE �B¡B
¢ABÁ0E Â	FÂ
BÂ	E ÂB D;Ä5E Ä;E Å E Å	E?Å.E:Å:E?Å?Fz/user/bulk_updatez�The litellm-changed-by header enables tracking of actions performed by authorized users on behalf of other users, providing an audit trail for accountability)r  c              ƒ   óâ  K  — ddl m}m} |€t        dddi¬«      ‚| j                  rt        | j                  dd«      nd}|€)| j                  rt        d	„ | j                  D «       d«      }|�4|j                  t        j                  j                  k7  rt        d
d¬«      ‚g }| j                  �r| j                  �rú|j                  t        j                  j                  k7  rt        d
d¬«      ‚t        |«      j                  ddi¬«      ƒ d{  –—† }|st        dddi¬«      ‚d}t        |«      |kD  rt        ddd|› dt        |«      › d�i¬«      ‚| j                  j!                  d¬«      }	t#        |	| j                  ¬«      }
|
j%                  dd«       |
j%                  dd«       d}d}g }	 t'        |«      j(                  j+                  i |
¬«      ƒ d{  –—†  |D ]G  }|j-                  t/        |j0                  |j2                  dd|j0                  i|
¥¬«      «       |dz  }ŒI 	 t5        j6                  t9        j:                  |j0                  xs dd|xs |j0                  ||dt        |«      › d �t=        j>                  |
«      ¬!«      «       |dkD  r@tK        |t        |«      ||¬$«      S | j                  r| j                  }nt        ddd%i¬«      ‚|st        dddi¬«      ‚d}t        |«      |kD  rt        ddd|› dt        |«      › d�i¬«      ‚tM        tO        tP        tR           |«      ||¬&«      ƒ d{  –—† S 7 �Œ97 �Œp# t@        $ r }tC        jD                  d"|«       Y d}~ŒÚd}~ww xY w# t@        $ rd}tC        jF                  d#|«       |D ]>  }| j                  jI                  «       }|j0                  |_        |j-                  |«       Œ@ Y d}~�ŒJd}~ww xY w7 Œ¦­w)'aŒ  
    Bulk update multiple users at once.
    
    This endpoint allows updating multiple users in a single request. Each user update
    is processed independently - if some updates fail, others will still succeed.
    
    Parameters:
    - users: Optional[List[UpdateUserRequest]] - List of specific user update requests
    - all_users: Optional[bool] - Set to true to update all users in the system
    - user_updates: Optional[UpdateUserRequest] - Updates to apply when all_users=True
    
    Returns:
    - results: List of individual update results
    - total_requested: Total number of users requested for update
    - successful_updates: Number of successful updates
    - failed_updates: Number of failed updates
    
    Example request for specific users:
    ```bash
    curl --location 'http://0.0.0.0:4000/user/bulk_update'     --header 'Authorization: Bearer sk-1234'     --header 'Content-Type: application/json'     --data '{
        "users": [
            {
                "user_id": "user1",
                "user_role": "internal_user",
                "max_budget": 100.0
            },
            {
                "user_email": "user2@example.com", 
                "user_role": "internal_user_viewer",
                "max_budget": 50.0
            }
        ]
    }'
    ```
    
    Example request for all users:
    ```bash
    curl --location 'http://0.0.0.0:4000/user/bulk_update'     --header 'Authorization: Bearer sk-1234'     --header 'Content-Type: application/json'     --data '{
        "all_users": true,
        "user_updates": {
            "user_role": "internal_user",
            "max_budget": 50.0
        }
    }'
    ```
    r   rË  Nrä   r’   rŒ   r”   r{   c              3   óN   K  — | ]  }|j                   €Œ|j                   –— Œ y ­wrF   )r{   )rÔ   Úus     rI   rÖ   z#bulk_user_update.<locals>.<genexpr>Ù  s   è ø€ ÒV¨1¸a¿k¹kÑ>U˜1Ÿ;�;ÑVùs   ‚%”%ræ   r´  z/Only proxy admins can update all users at once.ry  Údesc)ÚorderrÆ   zNo users found to updatezMaximum z% users can be updated at once. Found z users.TrÌ  rÍ  ro   r    ©r‘   r_   rì  r  rê   r¥  zUpdated z usersr¦  z#Failed to create bulk audit log: %sz!Failed to perform bulk update: %srï  zkMust specify either 'users' for individual updates or 'all_users=True' with 'user_updates' for bulk updates)rê  r©   r   )*rì   r¡  rB   r   Úuser_updatesrš   ÚusersÚnextr{   r|   r}   r~   Ú	all_usersrJ   rq  r�   rQ  rž  rh   r2   rG   Úupdate_manyr¹   r8   ro   r    r¼   r÷   r   r«  ró   Údumpsr—   r   r­  rù   Ú
model_copyr6   rô  r   r€   ÚUpdateUserRequest)r_   r©   r   r¡  rB   Ú
_bulk_rolerê  Úall_users_in_dbÚMAX_BATCH_SIZErm   rœ  rñ  rò  r†  rq   r°  rÎ   Úuser_update_requests                     rI   Úbulk_user_updater  ‹  sO  è ø€ ÷F SàÐÜØØÐ5Ð6ô
ð 	
ð CG×BSÒBS”˜×*Ñ*¨K¸Ô>ÐY]€JØÐ˜dŸjšjÜÑV°·
±
ÔVÐX\Ó]ˆ
ØÐÐ"3×"=Ñ"=ÔAQ×A]ÑA]×AcÑAcÒ"cÜØØ=ô
ð 	
ð Y[€Oà‡~ƒ~˜$×+Ó+à×&Ñ&Ô*:×*FÑ*F×*LÑ*LÒLÜØØHôð ô
 (3°=Ó'A×'KÑ'KÐS_ÐagÐRhÐ'KÓ'i×!iˆáÜØØÐ!;Ð<ôð ð ˆÜˆÓ .Ò0ÜØà˜x¨Ð'7Ð7\Ô]`ÐapÓ]qÐ\rÐryÐzðôð ð "&×!2Ñ!2×!=Ñ!=ÈDÐ!=Ó!Qˆ	Ü7SØ d×&7Ñ&7ô8
Ðð
 	×Ñ˜y¨$Ô/Ø×Ñ˜|¨TÔ2àÐØ !ˆØ13ˆð)	<ä  Ó/×5Ñ5×AÑAØØ'ð Bó ÷ ð ð (ò 	(�Ø—‘Ü$Ø $§¡Ø#'§?¡?Ø $Ø&/°·±Ð%TÐASÐ%Tô	ôð # aÑ'Ñ"ð	(ðaÜ×#Ñ#Ü,×KÑKØ 1× 9Ñ 9Ò ?¸RØ(Ø+=Ò+ZÐAR×AZÑAZØ*;Ø1IØ'/´°OÓ0DÐ/EÀVÐ%LÜ$(§J¡JÐ/AÓ$Bôô
ð,  Ò!Ü)ØÜ # OÓ 4Ø#5Ø-ô	ð ð 
�ŠØŸ*™*‰äØàð  Gðô
ð 	
ñ ÜØØÐ7Ð8ô
ð 	
ð €NÜ
ˆ?Ó˜nÒ,ÜØà˜8 NÐ#3Ð3XÔY\Ð]lÓYmÐXnÐnuÐvðô
ð 	
ô -ÜœTÔ"3Ñ4°oÓFØ+Ø-ô÷ ð ð[ "jùðDúô< ò aÜ$×,Ñ,Ð-RÐT_×`Ñ`ûðaûô ò 	<Ü ×*Ñ*Ð+NÐPQÔRà'ò <�Ø&*×&7Ñ&7×&BÑ&BÓ&DÐ#Ø.2¯l©lÐ#Ô+Ø×&Ñ&Ð':Õ;ö<ûð	<úðTúsƒ   ‚DO/ÄMÄB!O/Æ5)M= ÇMÇAM= È0A+M ÊB+O/ÍO-ÍO/ÍM= Í	M:ÍM5Í0M= Í5M:Í:M= Í=	O*ÎAO%ÏO/Ï%O*Ï*O/Úuser_idsc              ƒ   óº   K  — ddl m} |rt        |«      dk(  ri S i }|D ]5  }t        | «      j	                  |ddidd|iigdœ¬«      ƒ d{  –—† }|||<   Œ7 |S 7 Œ­w)a  
    Helper function to get the count of keys for each user using Prisma's count method.

    Args:
        prisma_client: The Prisma client instance
        user_ids: List of user IDs to get key counts for

    Returns:
        Dictionary mapping user_id to key count
    r   r�  rÀ   NÚnot)ro   ÚORr�   )r“  rŽ  r�   rR   Úcount)rB   r  rŽ  Úresultro   r  s         rI   Úget_user_key_countsr  _  sŽ   è ø€ õ ;á”s˜8“}¨Ò)Øˆ	à$&€Fð ò 
 ˆÜ/°Ó>×DÑDà"à Ð%Ø Ð(@Ð AÐBðñð Eó 
÷ 
ˆð  ˆˆwŠð
 ð €Mð
ús   ‚A	AÁAÁAÚsort_byÚ
sort_orderc                 óÊ   — i }| €y g d¢}| |vr!t        ddddj                  |«      › �i¬«      ‚|j                  «       dvrt        dddi¬«      ‚|j                  «       || <   |S )	N)ro   r    ry  rA  rw  r{   rÆ   r’   z%Invalid sort column. Must be one of: z, r”   )Úascrø  z+Invalid sort order. Must be 'asc' or 'desc')r   ÚjoinÚlower)r  r  Úorder_byÚvalid_columnss       rI   Ú_validate_sort_paramsr  „  s�   € Ø&(€Hà€Øò€Mð �mÑ#ÜØØÐDÀTÇYÁYÈ}ÓE]ÐD^Ð_Ð`ô
ð 	
ð ×ÑÓ Ñ0ÜØØÐJÐKô
ð 	
ð
 #×(Ñ(Ó*€HˆWÑà€OrL   rû   rÃ  r>   Úproxy_logging_objzProxyLogging | Nonec              ƒ   ó‚  K  — t        | «      r|S | j                  €t        dddi¬«      ‚	 t        | j                  ||d|¬«      ƒ d{  –—† }|€t        dddi¬«      ‚|j
                  xs g D �cg c]5  }|j                  t        j                  j                  k(  r|j                  ‘Œ7 }}|st        dddi¬«      ‚|rKt        d„ |j                  d	«      D «       «      }t        |t        |«      z  «      }	|	st        ddd
i¬«      ‚|	}d	j                  |«      S 7 ŒÒ# t        $ r t        dddi¬«      ‚w xY wc c}w ­w)a  
    Authorize the /user/list request and return the (possibly scoped) organization_ids string.

    - Proxy admins: returns organization_ids unchanged (may be None).
    - Org admins: returns comma-separated org IDs scoped to their allowed orgs.
    - Others: raises 403.
    Nræ   r’   z9Only proxy admins and organization admins can list users.r”   F©ro   rB   rÃ  Úuser_id_upsertr  c              3   ó^   K  — | ]%  }|j                  «       sŒ|j                  «       –— Œ' y ­wrF   )r˜   )rÔ   Úoids     rI   rÖ   z/_authorize_user_list_request.<locals>.<genexpr>Ú  s"   è ø€ Òa¨sÐUX×U^ÑU^ÕU`˜sŸy™yŸ{Ñaùs   ‚-˜-ú,zBYou do not have org_admin access to the requested organization(s).)r    ro   r   r   rÝ   Úorganization_membershipsr{   r|   Ú	ORG_ADMINr~   r­   r™  Úsplitr€   r  )
r©   rû   rB   rÃ  r  rs  ÚmÚallowed_org_idsÚ	requestedr9  s
             rI   Ú_authorize_user_list_requestr%  ¤  sˆ  è ø€ ô Ð-Ô.ØÐà× Ñ Ð(ÜØØÐXÐYô
ð 	
ð
Ü#2Ø%×-Ñ-Ø'Ø1Ø Ø/ô$
÷ 
ˆð ÐÜØØÐXÐYô
ð 	
ð ×6Ñ6Ò<¸"öàØ�;‰;Ô*×4Ñ4×:Ñ:Ò:ð 	
×Óð€Oð ñ
 ÜØØÐXÐYô
ð 	
ñ ÜÑaÐ6F×6LÑ6LÈSÓ6QÔaÓaˆ	Ü" 9¬s°?Ó/CÑ#CÓDˆÙÜØØÐ!eÐfôð ð 'ˆà�8‰8�OÓ$Ð$ðQ
ùô ò 
ÜØØÐXÐYô
ð 	
ð
üòùs;   ‚)D?¬D Á	DÁ
D Á#D?Á1:D:Â+A1D?ÄD ÄD7Ä7D?z
/user/listzFilter users by rolezGet list of users by user_idsz Get list of users by sso_user_idz#Filter users by partial email matchzFilter users by team idr  zPage number)rV  Úger  é   éd   zNumber of items per page)rV  r&  Úler  zGColumn to sort by (e.g. 'user_id', 'user_email', 'created_at', 'spend')r  zSort order ('asc' or 'desc')zIFilter users by organization membership. Comma-separated list of org IDs.r¬   Ússo_user_idsrÕ   ÚpageÚ	page_sizec              ƒ   óR  K  — ddl m}m}m} |€t	        ddd|› �i¬«      ‚t        |
|	|||¬«      ƒ d{  –—† }	|d	z
  |z  }i }| r| |d
<   |rnt        |t        «      r^|j                  d«      D �cg c]#  }|j                  «       sŒ|j                  «       ‘Œ% }}t        |«      d	k(  r|d   ddœ|d<   nd|i|d<   |�t        |t        «      r|ddœ|d<   |�t        |t        «      rd|i|d<   |�Tt        |t        «      rD|j                  d«      D �cg c]#  }|j                  «       sŒ|j                  «       ‘Œ% }}d|i|d<   |	rJ|	j                  d«      D �cg c]#  }|j                  «       sŒ|j                  «       ‘Œ% }}|rddd|iii|d<   |j                  «       D ��ci c]  \  }}|€Œ	||“Œ }}}|�t        |t        «      rt        ||«      nd}t        |«      j                  j                  ||||r|nddi¬«      ƒ d{  –—† }t        |«      j                  j!                  |¬«      ƒ d{  –—† }t#        ||D �cg c]  }|j$                  ‘Œ c}«      ƒ d{  –—† }t'        j(                  d|«       | |z   }g }|D ]s  }|j+                  «       }t-        |j/                  d«      «      |d<   |j1                  t2        j5                  i |¥d|j/                  |j$                  d«      i¥«      «       Œu |||||dœS 7 �ŒÏc c}w c c}w c c}w c c}}w 7 �Œ7 Œêc c}w 7 ŒÅ­w)aú  
    Get a paginated list of users with filtering and sorting options.

    Parameters:
        role: Optional[str]
            Filter users by role. Can be one of:
            - proxy_admin
            - proxy_admin_viewer
            - internal_user
            - internal_user_viewer
        user_ids: Optional[str]
            Get list of users by user_ids. Comma separated list of user_ids.
        sso_ids: Optional[str]
            Get list of users by sso_ids. Comma separated list of sso_ids.
        user_email: Optional[str]
            Filter users by partial email match
        team: Optional[str]
            Filter users by team id. Will match if user has this team in their teams array.
        page: int
            The page number to return
        page_size: int
            The number of items per page
        sort_by: Optional[str]
            Column to sort by (e.g. 'user_id', 'user_email', 'created_at', 'spend')
        sort_order: Optional[str]
            Sort order ('asc' or 'desc')
    r   ©rB   r  rÃ  Nrä   r’   zNo db connected. prisma client=r”   )r©   rû   rB   rÃ  r  r  r{   r  rŽ   ©Úcontainsr�   ro   ro  r    Úhasrv   r{  Úsomer­   r  ry  rø  ©r‘   ÚskipÚtakerù  r�   zTotal count of users: %sr7  Ú	key_count)rü  Útotalr+  r,  Útotal_pages)rì   rB   r  rÃ  r   r%  rf   rw   r!  r˜   r�   r   r  r2   rG   rq  r  r  ro   r   rÊ   rQ  r<  ri   r¹   ÚLiteLLM_UserTableWithKeyCountrö   ) r¬   r  r*  r    rÕ   r+  r,  r  r  rû   r©   rB   r  rÃ  r4  Úwhere_conditionsÚuidÚuser_id_listÚsidÚsso_id_listr  Úorg_id_listr:  r;  r  rü  Útotal_countrq   Úuser_key_countsr8  Ú	user_listÚ	user_dumps                                    rI   Ú	get_usersrD  æ  s�  è ø€ ÷hñ ð ÐÜØØÐ>¸}¸oÐNÐOô
ð 	
ô :Ø+Ø)Ø#Ø-Ø+ô÷ Ðð ˜!‘8˜yÑ(€Dð +-ÐáØ(,Ð˜Ñ%á”J˜x¬Ô-Ø6>·n±nÀSÓ6IÖY¨sÈSÏYÉYÍ[˜sŸy™y�{ÐYˆÐYÜˆ|Ó Ò!à(¨™OØ%ñ+Ð˜YÒ'ð �lð+Ð˜YÑ'ð Ð¤*¨Z¼Ô"=à"Ø!ñ*
Ð˜Ñ&ð
 ÐœJ t¬SÔ1à�4ð%
Ð˜Ñ!ð Ð¤J¨|¼SÔ$AØ5A×5GÑ5GÈÓ5LÖ\¨cÐPS×PYÑPYÕP[˜cŸi™i�kÐ\ˆÐ\à�+ð+
Ð˜Ñ'ñ Ø5E×5KÑ5KÈCÓ5PÖ`¨cÐTW×T]ÑT]ÕT_˜cŸi™i�kÐ`ˆÐ`ÙØ<BÐEVÐY]Ð_jÐXkÐDlÐ;mÐÐ7Ñ8ð *:×)?Ñ)?Ó)A×S¡  AÀQÁ]˜˜1™ÐSÐÑSð
 7>Ð6IÌjÐY`ÔbeÔNfÔ˜g zÔ2Ðlpð ô ESÐS`ÓDa×DgÑDg×DqÑDqØØØÙ#‰x¨,¸Ð)?ð	 Eró E÷ ?€Eô %3°=Ó$A×$GÑ$G×$MÑ$MÐTdÐ$MÓ$e×e€Kô $7°}Ð`eÖFfÐX\ÀtÇ|Ã|ÒFfÓ#g×g€Oä×ÑÐ9¸;ÔGð (˜<¨9Ñ4Ð5€Kð 68€IØò 
ˆØ—O‘OÓ%ˆ	Ü @ÀÇÁÈzÓAZÓ [ˆ	�*ÑØ×ÑÜ)×8Ñ8ØP�9ÐP˜k¨?×+>Ñ+>¸t¿|¹|ÈQÓ+OÑPóõ	
ð
ð ØØØØ"ñð ðsûò$ Zùò. ]ùò aùó
 Tð?ùð fúò GgÐgúsœ   ‚2L'´Lµ:L'Á/LÂLÂA;L'ÄLÄ(LÄ:L'ÅLÅ.LÆ "L'Æ"
LÆ-LÆ2AL'ÈLÈ,L'È3LÈ4L'ÉL 
É
L'ÉL%É B$L'ÌL'ÌL'Ì L'z/user/deletec              ƒ   ó^
  K  — ddl m} ddlm}m} ddlm}m}m} |€t        dddi¬	«      ‚| j                  €t        d
ddi¬	«      ‚|j                  t        j                  j                  k(  }	t        «       }
|	s�|j                   rHt#        |«      j%                  |j                   t        j&                  j                  dœ¬«      ƒ d{  –—† ng }|D �ch c]  }|j(                  sŒ|j(                  ’Œ }
}|
st        dddi¬	«      ‚i }|	s‚t#        |«      j%                  dd| j                  ii¬«      ƒ d{  –—† }|D ]L  }|j(                  sŒ|j+                  |j                   t        «       «      j-                  |j(                  «       ŒN | j                  D �]T  }t/        |«      j0                  j3                  d|i¬«      ƒ d{  –—† }|€t        ddd|› �i¬	«      ‚|	s@|j5                  |t        «       «      }|r|j7                  |
«      st        ddd|› d�i¬	«      ‚ |«       r�|j9                  d¬«      }t;        j<                   |t?        tA        tC        jD                  «       «      tG        jH                  tJ        jL                  «       ||||¬«      |jN                  tP        jR                  |dd|¬«	      ¬«      «       tU        |«      j0                  j%                  dd|jV                  ii¬«      ƒ d{  –—† }g }|D ]ª  } |tX        j[                  |j]                  «       «      t_        |j`                  |j                   |jb                  ¬«      ¬«      \  }}|sŒ^|D �cg c]  }|j]                  «       ‘Œ }}|je                  |j`                  tg        jh                  |«      f«       Œ¬ |D ]7  \  }}tU        |«      j0                  jk                  d|id |i¬!«      ƒ d{  –—†  Œ9 �ŒW tm        |«      jo                  dd| j                  ii¬«      ƒ d{  –—†  tq        |«      jo                  d"dd| j                  iid#d| j                  iid$d| j                  iigi¬«      ƒ d{  –—†  t#        |«      jo                  dd| j                  ii¬«      ƒ d{  –—†  ts        |«      jo                  dd| j                  ii¬«      ƒ d{  –—†  tu        |«      jo                  dd| j                  ii¬«      ƒ d{  –—† }|S 7 �Œ@c c}w 7 �ŒÚ7 �ŒM7 �Œc c}w 7 �Œ87 �Œ7 Œµ7 Œ†7 ŒW7 Œ(­w)%a{  
    delete user and associated user keys

    ```
    curl --location 'http://0.0.0.0:4000/user/delete' 
    --header 'Authorization: Bearer sk-1234' 
    --header 'Content-Type: application/json' 
    --data-raw '{
        "user_ids": ["45e3e396-ee08-4a61-a88e-16b3ce7e0849"]
    }'
    ```

    Parameters:
    - user_ids: List[str] - The list of user id's to be deleted.
    r   )Ú_cleanup_members_with_roles)Úget_audit_log_changed_byÚis_audit_logging_enabled)Úcreate_audit_log_for_updater¡  rB   Nrä   r’   úNo db connectedr”   rÆ   zNo user id passed in)ro   r{   r�   ræ   z5Only PROXY_ADMIN or ORG_ADMIN users may delete users.ro   ro  r[  zUser not found, passed user_id=r\  zk is not within your admin scope. Only PROXY_ADMIN may delete users outside your administered organizations.Tr£  )r   r©   r¡  Údeletedz{})	r¦   rz  Ú
changed_byÚchanged_by_api_keyrr   Ú	object_idr§  Úupdated_valuesr¨  )Úrequest_datarÀ   )rÀ   ro   r    )Úexisting_team_rowr_   Úmembers_with_rolesrú  r  Ú
created_byÚ
updated_by);rÇ   rF  Ú+litellm.proxy.management_helpers.audit_logsrG  rH  rì   rI  r¡  rB   r   r  r{   r|   r}   r~   r™  ro   rU   rq  r   r­   Ú
setdefaultÚaddr2   rG   rm  ri   Úissubsetr¬  r¼   r÷   ÚLiteLLM_AuditLogsrw   r   rx   r   Únowr   ÚutcÚapi_keyÚLitellmTableNamesÚUSER_TABLE_NAMEr1   rv   rr  rö   rQ  ÚTeamMemberDeleteRequestrÀ   r    r¹   ró   r   ÚupdaterR   Údelete_manyrX   r^   rJ   )r_   r©   r   rF  rG  rH  rI  r¡  rB   Úcaller_is_proxy_adminÚcaller_admin_org_idsÚcaller_membershipsr"  Útarget_org_ids_by_userÚall_target_membershipsro   r}  Útarget_org_idsÚ	_user_rowÚfetch_all_teamsÚteams_to_updaterÕ   Úremoved_team_membersÚnew_team_membersÚ_db_new_team_membersrÀ   rR  Údeleted_userss                               rI   Údelete_userro  ‰  sz  è ø€ õ@÷÷ñ ð ÐÜ¨°WÐ>OÐ4PÔQÐQà‡}�}ÐÜ¨°WÐ>TÐ4UÔVÐVð $5×#>Ñ#>ÔBR×B^ÑB^×BdÑBdÑ#dÐÜ%(£UÐÙ ð !×(Ò(ô 1°Ó?×IÑIà0×8Ñ8Ü!1×!;Ñ!;×!AÑ!Añð Jó ÷ ð ð ð 	ð <NÖc°aÐQR×QbÓQb × 1Ó 1ÐcÐÐcÙ#ÜØØÐ!XÐYôð ð :<ÐÙ Ü.LÈ]Ó.[×.eÑ.eØ˜t T§]¡]Ð3Ð4ð /fó /
÷ )
Ðð (ò 	WˆAØ×$Ò$ØØ"×-Ñ-¨a¯i©i¼»Ó?×CÑCÀA×DUÑDUÕVð	Wð —=‘=ó KˆÜ'¨Ó6×<Ñ<×HÑHÐPYÐ[bÐOcÐHÓd×dˆàÐÜØØÐ#BÀ7À)Ð!LÐMôð ñ
 %Ø3×7Ñ7¸ÄÃÓGˆNñ "¨×)@Ñ)@ÐAUÔ)VÜ#Ø #àØ# G 9ð -:ð :ðô	ð 	ñ $Ô%à ×0Ñ0¸dÐ0ÓCˆIä×ÑÙ+Ü!2ÜœtŸz™z›|Ó,Ü#+§<¡<´·±Ó#=Ù#;Ø/AØ.?Ø5Mô$ð
 ,=×+DÑ+DÜ#4×#DÑ#DØ")Ø(Ø'+Ø%.ô"ôôô* LZØóL
ç
‰%—	‘	 ¨T°8·>±>Ð,BÐ C�	ÓD÷FEˆð 24ˆØ#ò 	YˆDÙ5PÜ"3×"BÑ"BÀ4Ç?Á?ÓCTÓ"UÜ,Ø ŸL™LØ$×,Ñ,Ø'×2Ñ2ôô6Ñ2Ð Ð"2ò $ØL\Ö3]Àq°A·L±LµNÐ3]Ð$Ð3]Ø×&Ñ&¨¯©´d·j±jÐAUÓ6VÐ'WÕXð	Yð ,;ò 	Ñ'ˆGÐ'Ü  Ó/×5Ñ5×<Ñ<Ø  'Ð*Ø*Ð,>Ð?ð =ó ÷ ñ ò	ðOKô^ $ MÓ
2×
>Ñ
>ÀiÐRVÐX\×XeÑXeÐQfÐEgÐ
>Ó
h×hÐhô ! Ó
/×
;Ñ
;àØ˜T 4§=¡=Ð1Ð2Ø  d§m¡mÐ4Ð5Ø  d§m¡mÐ4Ð5ðð
ð <ó ÷ ð ô )¨Ó
7×
CÑ
CÈ9ÐW[Ð]a×]jÑ]jÐVkÐJlÐ
CÓ
m×mÐmô ! Ó
/×
;Ñ
;À9ÈtÐUY×UbÑUbÐNcÐBdÐ
;Ó
e×eÐeô "-¨]Ó!;×!GÑ!GÈyÐ[_Ðae×anÑanÐZoÐNpÐ!GÓ!q×q€MàÐðEûò  dð)
ùð eùðfFEûò 4^ðùð iùðøð nøð føð rúsÞ   ‚CT-Ã	T	Ã

T-ÃTÃ&TÃ4AT-Ä7TÄ8BT-ÇTÇD4T-Ë<TË=A%T-Í#T-Í'TÍ>A)T-Ï'TÏ(5T-ÐT"ÐAT-Ñ/T%Ñ00T-Ò T'Ò!0T-ÓT)Ó0T-ÔT+ÔT-ÔT-ÔT-ÔT-ÔT-Ô"T-Ô%T-Ô'T-Ô)T-Ô+T-r­   z,prisma_models.LiteLLM_OrganizationMembershipc              ƒ   óH  K  — ddl m} |€t        d«      ‚	 t        |«      j	                  d|i¬«      ƒ d{  –—† }|€t        d|› �«      ‚t        |«      j                  j                  | ||dœ¬	«      ƒ d{  –—† }|S 7 ŒG7 Œ# t        $ r}t        d
|› �«      ‚d}~ww xY w­w)a  
    Helper function to add an internal user to an organization

    Adds the user to LiteLLM_OrganizationMembership table

    - Checks if organization_id exists

    Raises:
    - Exception if database not connected
    - Exception if user_id or organization_id not found
    r   ri  NrŒ   r­   r�   z/Organization not found, passed organization_id=)ro   r­   r{   rb   z$Failed to add user to organization: )rì   rB   r—   r[   rm  r/   rG   Úcreate)ro   r­   r{   rB   Úorganization_rowÚnew_membershiprÎ   s          rI   Ú!add_internal_user_to_organizationrt  K	  sÛ   è ø€ õ  9àÐÜÐ0Ó1Ð1ðDä(;¸MÓ(J×(VÑ(VØ$ oÐ6ð )Wó )
÷ #
Ðð Ð#ÜÐMÈoÐM^Ð_Ó`Ð`ô UuØóU
ç
‰%—‘à"Ø#2Ø&ñð ó 
÷	O
ˆð Ðð%#
øð	O
ùô ò DÜÐ>¸q¸cÐBÓCÐCûðDüsK   ‚B"— B ·A?¸A B Á8BÁ9B Á>B"Á?B ÂB Â	BÂBÂBÂB"c              ƒ   óÚ  K  — ddl m}  |«       ƒ d{  –—† }|j                  dd«      syt        | «      ryd}| j                  �#	 t        | j                  ||d|¬«      ƒ d{  –—† }g }|�'|j                  xs g D �	cg c]  }	|	j                  ‘Œ }}	|r|S |xs | j                  }
|
�t        | |
|||«      ƒ d{  –—† S t        ddd	i¬
«      ‚7 Œ»7 Œm# t        $ r d}Y Œxw xY wc c}	w 7 Œ-­w)zÄ
    Return a list of org IDs to filter by, or ``None`` for no filter.

    Reads the ``scope_user_search_to_org`` UI-setting flag and applies
    role-based access rules when the flag is ON.
    r   )Úget_ui_settings_cachedNÚscope_user_search_to_orgFr  ræ   r’   zmscope_user_search_to_org is enabled. Only proxy admins, organization admins, or team admins can search users.r”   )Ú7litellm.proxy.ui_crud_endpoints.proxy_setting_endpointsrv  ri   r    ro   r   rÝ   r  r­   rÀ   Ú_resolve_team_org_filterr   )r©   rÀ   rB   rÃ  r  rv  Úui_settingsrs  Úmember_org_idsr"  Úresolved_team_ids              rI   Ú#_resolve_org_filter_for_user_searchr}  y	  s4  è ø€ õñ  6Ó7×7€KØ�?‰?Ð5°uÔ=ØäÐ-Ô.Øð €KØ× Ñ Ð,ð		Ü /Ø)×1Ñ1Ø+Ø#5Ø$Ø"3ô!÷ ˆKð !#€NØÐØ6A×6ZÑ6ZÒ6`Ð^`Öb°˜!×+Ó+ÐbˆÐbáØÐð &ÒBÐ):×)BÑ)BÐØÐ#Ü-ØØØØØó
÷ 
ð 	
ô Øàð  Eð
ôð ðS 8øðùô ò 	ØŠKð	üò cð
ús]   ‚C+“C”1C+ÁC Á#CÁ$C Á(C+Á>C$Â*C+Â;C)Â<C+ÃC ÃC!ÃC+Ã C!Ã!	C+c              ƒ   ó
  K  — ddl m} 	 t        ||||¬«      ƒ d{  –—† } || |«      st        ddd
i¬	«      ‚|j                  r|j                  gS t        dddi¬	«      ‚7 ŒD# t        $ r t        ddd|› d�i¬	«      ‚w xY w­w)zCLook up the team and return its org as a filter list, or raise 403.r   )r   )rÀ   rB   rÃ  r  Nræ   r’   z.scope_user_search_to_org is enabled but team 'z' was not found.r”   zWscope_user_search_to_org is enabled. You must be an admin of this team to search users.z‚scope_user_search_to_org is enabled and this team is not part of an organization. Contact your proxy admin to adjust this setting.)Ú/litellm.proxy.management_endpoints.common_utilsr   r   r   r­   )r©   rÀ   rB   rÃ  r  r   rp  s          rI   ry  ry  »	  sÂ   è ø€ õ Tð
Ü /ØØ'Ø1Ø/ô	!
÷ 
ˆñ Ð0°(Ô;ÜØØÐvÐwô
ð 	
ð
 ×ÒØ×(Ñ(Ð)Ð)ä
Øàð  Zð
ôð ð+
ùô ò 
ÜØØÐMÈgÈYÐVfÐgÐhô
ð 	
ð
üs,   ‚BŠA# œA!�A# ¡A BÁ!A# Á#B Â Bz/user/filter/uiéÈ   Úmodel)rß   rà   r  Ú	responsesz$User email in the request parametersuJ   Team ID â€” used when a team admin searches for users to add to their teamzPage number for pagination)rV  r  r&  é2   )rV  r  r&  r)  c              ƒ   ó  K  — ddl m}m}m} |€t	        dddi¬«      ‚	 t        |||||¬«      ƒ d{  –—† }	|d	z
  |z  }
i }| r| d
dœ|d<   |r|d
dœ|d<   |	�ddd|	iii|d<   t        |«      j                  ||
|ddi¬«      ƒ d{  –—† }|sg S |D �cg c]%  }t        j                  |j                  «       «      ‘Œ' c}S 7 ŒŒ7 Œ;c c}w # t        $ r ‚ t        $ r+}t        j                  d|«       t	        dd|› �¬«      ‚d}~ww xY w­w)aä  
    Filter users based on partial match of user_id or email with pagination.

    Behaviour depends on the ``scope_user_search_to_org`` UI-setting flag
    (stored in the ``litellm_uisettings`` table):

    * **Flag OFF (default):** any authenticated user can search all users.
    * **Flag ON:**
      - Proxy admins see all users.
      - Org admins see only users in their org(s).
      - Team admins for an org-bound team see users in that org.
      - Others receive a 403.
    r   r.  Nrä   r’   rJ  r”   )r©   rÀ   rB   rÃ  r  r  rŽ   r/  ro   r    r2  r­   ro  r  ry  rø  r3  zError searching users: %szError searching users: )rì   rB   r  rÃ  r   r}  rJ   rq  ÚLiteLLM_UserTableFilteredrö   rQ  r—   r   rù   )ro   r    rÀ   r+  r,  r©   rB   r  rÃ  Úorg_filter_idsr4  r:  rü  rq   rÎ   s                  rI   Úui_view_usersr‡  ã	  st  è ø€ ÷Bñ ð ÐÜ¨°WÐ>OÐ4PÔQÐQð0SÜ&IØ/ØØ'Ø1Ø/ô'
÷ !
ˆð ˜a‘x 9Ñ,ˆð MOÐáà#Ø%ñ+Ð˜YÑ'ñ
 à&Ø%ñ.Ð˜\Ñ*ð Ð%Ø<BÐEVÐY]Ð_mÐXnÐDoÐ;pÐÐ7Ñ8ô )¨Ó7×AÑAØ"ØØØ Ð(ð	 Bó 
÷ 
ˆñ ØˆIàX]Ö^ÐPTÔ)×8Ñ8¸¿¹Ó9JÕKÒ^Ð^ðS!
øð>
úò _øäò ØÜò SÜ×&Ñ&Ð'BÀAÔFÜ¨Ð6MÈaÈSÐ4QÔRÐRûðSüsi   ‚DŸC ²B?³AC ÂCÂC ÂDÂC Â*CÂ<C Â>DÂ?C ÃC ÃC ÃDÃ&D Ä DÄDÚrecordsc           
   ƒ   óN  K  — |D �ch c]%  }t        t        |dd«      x}t        «      sŒ!|sŒ$|’Œ' }}|si S t        | «      j	                  ddt        |«      ii¬«      ƒ d{  –—† }|D �ci c]&  }|j                  |j                  |j                  dœ“Œ( c}S c c}w 7 Œ;c c}w ­w)z—Map each user_id on the page to its email/alias so the Usage dashboard can
    label the 'Spend Per User' chart with the email instead of the raw UUID.ro   Nro  r�   )r    rw  )	rf   rš   rw   rJ   rq  r€   ro   r    rw  )rB   rˆ  Úrecordro   r  rü  rq   s          rI   Ú_resolve_user_email_metadatar‹  C
  s«   è ø€ ð &öØ¬¼wÀvÈyÐZ^Ó?_Ð4_°GÔadÕ)eÒjqŠð€Hð ñ Øˆ	Ü$ ]Ó3×=Ñ=ÀYÐQUÔW[Ð\dÓWeÐPfÐDgÐ=Óh×h€EØejÖkÐ]aˆD�L‰L¨¯©ÈÏÉÑXÑXÒkÐkùòð
 iúÚkùs7   ‚B%‡"BªB­B±1B%Á"BÁ#B%Á++B Â	B%Â B%z/user/daily/activityzBudget & Spend TrackingzStart date in YYYY-MM-DD formatzEnd date in YYYY-MM-DD formatzFilter by specific modelzFilter by specific API keyz}Filter by specific user ID. Admins can filter by any user or omit for global view. Non-admins must provide their own user_id.zItems per pageiè  zrTimezone offset in minutes from UTC (e.g., 480 for PST). Matches JavaScript's Date.getTimezoneOffset() convention.zìWhen the range ends on the caller's current local day, extend it to today's UTC bucket so spend written after the caller's local midnight (in UTC terms) is included. Requires the timezone parameter. Historical ranges are never extended.Ú
start_dateÚend_dater\  r   Úinclude_current_utc_dayc
              ƒ   ó   ‡K  — ddl mŠ ‰€'t        ddt        j                  j
                  i¬«      ‚| �|€t        t        j                  ddi¬«      ‚	 t        |	«      }
|
r|}n3t        |	«      }|€|}||k7  rt        t        j                  ddi¬«      ‚|}t        ‰d	d
|d| |||||||ˆfd„¬«      ƒ d{  –—† S 7 Œ# t        $ r ‚ t        $ r;}t        j                  d|«       t        t        j                  dd|› �i¬«      ‚d}~ww xY w­w)ad  
    [BETA] This is a beta endpoint. It will change.

    Meant to optimize querying spend data for analytics for a user.

    Returns:
    (by date)
    - spend
    - prompt_tokens
    - completion_tokens
    - cache_read_input_tokens
    - cache_creation_input_tokens
    - total_tokens
    - api_requests
    - breakdown by model, api_key, provider
    r   ri  Nrä   r’   r”   ú&Please provide start_date and end_dateú3Non-admin users can only view their own spend data.Úlitellm_dailyuserspendro   c                 ó   •— t        ‰| «      S rF   )r‹  )rˆ  rB   s    €rI   rJ  z)get_user_daily_activity.<locals>.<lambda>¹
  s   ø€ Ô4PÐQ^Ð`gÓ4h€ rL   )rB   rr   Úentity_id_fieldr`  Úentity_metadata_fieldrŒ  r�  r�  r\  r+  r,  Útimezone_offset_minutesrŽ  Úresolve_entity_metadataz./spend/daily/analytics: Exception occured - %súFailed to fetch analytics: )rì   rB   r   rí   rî   r~   r   rè  r    r!   r$  r   r—   r   rù   ÚHTTP_500_INTERNAL_SERVER_ERROR)rŒ  r�  r�  r\  ro   r+  r,  r   rŽ  r©   Úis_adminr`  Úcaller_user_idrÎ   rB   s                 @rI   Úget_user_daily_activityrœ  Q
  sT  øè ø€ õx 9àÐÜØØÔ.×EÑE×KÑKÐLô
ð 	
ð
 Ð˜XÐ-ÜÜ×3Ñ3ØÐEÐFô
ð 	
ð
(
Ü.Ð/@ÓAˆáØ‰Iä$HÐIZÓ$[ˆNØˆØ(�Ø˜.Ò(Ü#Ü &× 9Ñ 9Ø#Ð%ZÐ[ôð ð  ˆIä'Ø'Ø/Ø%ØØ"&Ø!ØØØØØØ$,Ø$;Û$hô
÷ 
ð 	
ð 
ùô" ò ØÜò 
Ü×&Ñ&Ð'WÐYZÔ[ÜÜ×=Ñ=ØÐ:¸1¸#Ð>Ð?ô
ð 	
ûð
üs=   ƒADÁA"B> Â7B<Â8B> Â;DÂ<B> Â>DÃ6DÄDÄDz/user/daily/activity/aggregatedc              ƒ   ó  K  — ddl m} |€'t        ddt        j                  j
                  i¬«      ‚| �|€t        t        j                  ddi¬«      ‚	 t        |«      }	|	r|}
n3t        |«      }|€|}||k7  rt        t        j                  ddi¬«      ‚|}
t        |d	d
|
d| |||||¬«      ƒ d{  –—† S 7 Œ# t        $ r ‚ t        $ r;}t        j                  d|«       t        t        j                  dd|› �i¬«      ‚d}~ww xY w­w)z³
    Aggregated analytics for a user's daily activity without pagination.
    Returns the same response shape as the paginated endpoint with page metadata set to single-page.
    r   ri  Nrä   r’   r”   r�  r‘  r’  ro   )rB   rr   r”  r`  r•  rŒ  r�  r�  r\  r–  rŽ  z7/user/daily/activity/aggregated: Exception occured - %sr˜  )rì   rB   r   rí   rî   r~   r   rè  r    r!   r$  r   r—   r   rù   r™  )rŒ  r�  r�  r\  ro   r   rŽ  r©   rB   rš  r`  r›  rÎ   s                rI   Ú"get_user_daily_activity_aggregatedrž  Æ
  sJ  è ø€ õ\ 9àÐÜØØÔ.×EÑE×KÑKÐLô
ð 	
ð
 Ð˜XÐ-ÜÜ×3Ñ3ØÐEÐFô
ð 	
ð
%
Ü.Ð/@ÓAˆáØ‰Iä$HÐIZÓ$[ˆNØˆØ(�Ø˜.Ò(Ü#Ü &× 9Ñ 9Ø#Ð%ZÐ[ôð ð  ˆIä2Ø'Ø/Ø%ØØ"&Ø!ØØØØ$,Ø$;ô
÷ 
ð 	
ð 
ùô ò ØÜò 
Ü×&Ñ&Ð'`ÐbcÔdÜÜ×=Ñ=ØÐ:¸1¸#Ð>Ð?ô
ð 	
ûð
üs=   ‚ADÁAB7 Â0B5Â1B7 Â4DÂ5B7 Â7DÃ	6C?Ã?DÄD)rB   rC   rD   z-TableActions[prisma_models.LiteLLM_UserTable])rB   rC   rD   z-TableActions[prisma_models.LiteLLM_TeamTable])rB   rC   rD   z5TableActions[prisma_models.LiteLLM_VerificationToken])rB   rC   rD   z:TableActions[prisma_models.LiteLLM_OrganizationMembership])rB   rC   rD   z2TableActions[prisma_models.LiteLLM_InvitationLink])rB   rC   rD   z5TableActions[prisma_models.LiteLLM_OrganizationTable])rB   rC   rD   z2TableActions[prisma_models.LiteLLM_TeamMembership])rD   N)NNrq   rF   )¸Ú__doc__r¼   ró   rå  Úcollections.abcr   r   r   r   r   Útypingr   r	   r
   r   Úfastapir   r   r   r   r   r   ry   Úlitellm._loggingr   Úlitellm._uuidr   Úlitellm.proxy._typesÚlitellm.proxy.auth.auth_checksr   r   Ú$litellm.proxy.auth.user_api_key_authr   Ú-litellm.proxy.common_utils.user_api_key_cacher   r   Ú,litellm.proxy.hooks.model_max_budget_limiterr   Ú/litellm.proxy.hooks.user_management_event_hooksr   Ú8litellm.proxy.management_endpoints.common_daily_activityr   r   r   r  r   r    r!   r"   r#   Ú;litellm.proxy.management_endpoints.key_management_endpointsr$   r%   r&   Ú8litellm.proxy.management_helpers.object_permission_utilsr'   r(   Ú&litellm.proxy.management_helpers.utilsr)   Úlitellm.proxy.utilsr*   r+   Ú,litellm.repositories.organization_repositoryr,   Ú%litellm.repositories.prisma_protocolsr-   Ú'litellm.repositories.table_repositoriesr.   r/   r0   Ú$litellm.repositories.team_repositoryr1   Ú$litellm.repositories.user_repositoryr2   Ú2litellm.repositories.verification_token_repositoryr3   Ú>litellm.types.proxy.management_endpoints.common_daily_activityr4   Ú@litellm.types.proxy.management_endpoints.internal_user_endpointsr5   r6   r7   r8   Ú0litellm.types.proxy.management_endpoints.scim_v2r9   r:   r;   ÚTYPE_CHECKINGÚprismar<   Úprisma_modelsr=   Úprisma_typesr>   rì   r?   r@   rA   Ú__annotations__rJ   rO   rR   rU   rX   r[   r^   rg   rc   rl   ÚNewUserRequestr†   rw   ÚboolrŸ   r¤   r§   r€   rò   r¿   ÚfloatrÏ   rÚ   rÛ   rÞ   Úpostrô   r   ri   r  rr  ÚTeamListResponseObjectÚLiteLLM_TeamMembershipr
  r  r  r"  r&  rÖ  r5  Ú	frozensetr6  Úobjectr<  r„  rR  rU  ÚQueryr'  ru  r|  r  rb  rN  r  Ú UpdateUserRequestNoUserIDorEmailrž  rP  r±  r¸  r¼  rÀ  rÉ  rÞ  rª  r¶  ré  rô  r  Úintr  r  r%  rD  ÚDeleteUserRequestro  r|   rt  r}  ry  r…  r‡  r‹  rœ  rž  rë   rL   rI   ú<module>rÊ     s‚  ðòó Û Û ß 8Ñ 8ß 'ß ,Ó ,ã ß N× Nã Ý 1Ý Ü "ß KÝ B÷õ VÝ T÷ñ ÷
õ ÷ñ ÷
õ Oß HÝ OÝ >÷ñ õ
 @Ý ?õõ÷ó ÷ñ ñ Ý.Ý,åMÝ7Ý0á“€ˆÓ ðØ(ðà4óðØ(ðà4óðØ(ðà<óðØ(ðàAóðØ(ðà9óðØ(ðà<óð!Ø(ð!à9ó!ð; ð ;¨$ó ;ó<ð!°ð !¸Nð !Ètó !ðR #Øò'Øð'à�t‘ð'ð )ð'ð
 ð'ð �‰:ð'ð 
ó'ðT
°#¸±*ð 
ÐMbð 
Ðgkó 
ð	¨C°$©Jð 	ÐG\ð 	Ðaeó 	ð 9Øð 9à˜‘9ð 9ð "ð 9ð &ó	 9ðN "Ø'+Ø*0ñ8Øð8àð8ð &ð8ð �d‘
ð	8ð
  ™ð8ð �Ñ'ó8ðv 4¨¡9¨tÐ4FÑ/GÑ#GÈ$Ñ#Nó ð09Øð9à�d‘
ð9ð &ð9ð �‰9�tÐ.Ñ/Ñ/ð	9ð
 "ó9ðB ‡�ØØ
$Ð	%ÙÐ+Ó,Ð-Ø"ð	 ó ð ñ )0Ð0AÓ(Bñw+Ø
ðw+à%òw+ó óðw+ðt ‡�ØØ
$Ð	%ØÙÐ+Ó,Ð-ð	 ó ñ )0Ð0AÓ(BñØ%òóðð:
ØÐ%Ñ&¨Ð.DÑ)EÑEÈÑLð
àð
ð Ð/Ñ/°$Ñ6ó
ð	˜sð 	 tó 	ð gð °#¸±*ó ð*¨'ð ¸CÀ$¹Jð È3ÐQUÉ:ó ð s¨T¡zð Ànð ÐY]ó ð<1Øð1à�4‰Zð1ð �T‰zð1ð &ð	1ð
 ˆ4Ð&Ñ'¨Ð.DÑ)EÈÑ)LÐLÑMó1ñh (1Ø!Ð#AÐCZÐ[ó(Ð ˜uó ð
	YØ�3˜�;Ñ $Ñ&ð	Yà	ˆ#ˆvˆ+Ñ˜Ñó	Yð$ CGñØ�4‰Zðà�T‰zðð Ð(Ñ
)¨DÑ
0ðð Ð*Ñ+ð	ð
 Ð(Ñ)¨DÑ0ðð !  d¨3°¨;Ñ&7Ð!7Ñ8¸4Ñ?ðð óð> ‡�ØØ
$Ð	%ÙÐ+Ó,Ð-Ø#ð	 ó ð ð (˜'Ÿ-š-°ÐBeÔfÙ(/Ð0AÓ(BñK+ØðK+à�4‰ZðK+ð &òK+ó óðK+ð\8Ø%ð8àð8ð .ó8ðv ‡�ØØ
$Ð	%ÙÐ+Ó,Ð-Ø%ð	 ó ð ð (˜'Ÿ-š-°ÐBeÔfÙ(/Ð0AÓ(BñX+ØðX+à�4‰ZðX+ð &òX+ó óðX+ðv;¸Nó ;ð|'Ø
Ð(Ñ
)¨DÑ
0ð'àÐ%Ñ&¨Ð.DÑ)EÑEÈÑLó'ðT.¨Dð .Ð8IÐLlÑ8lð .Ðquó .ðbyØ�3˜�8‰nðyà  4Ñ'ðyð ˜d™
ðyð &ð	yð
 " D™jðyð 
óyð<
Ø#ð
à%ð
ð ! 4Ñ'ð
ð 
ó	
ð8cØ  V Ñ,ðcà	ócð"	VÐ,=ð 	VÀ$ó 	Vðg°s¸T±zð gÐZ_Ð`cÐehÐ`hÑZið gÐnró gðB &*ñ]Ø#ð]à%ð]ð ˜d™
ð]ð 
ˆ#ˆsˆ(�^ó	]ð@Ø%ðà ðð 
óð ‡�ØØ
$Ð	%ÙÐ+Ó,Ð-ð ó ð
 ñ )0Ð0AÓ(BñR
Ø
ðR
à%òR
ó óðR
ðp &*ñ8GØÐ+Ñ,ð8Gà%ð8Gð ˜d™
ð8Gð ó	8Gðv ‡�ØØ
$Ð	%ÙÐ+Ó,Ð-Ø)ð	 ó ð ñ )0Ð0AÓ(BÙ%+Øð tô&ñJØ
ðJà%ðJð ˜d™
òJó óðJð^ "&ñ"Ø(ð"à�3‰i˜$Ñð"ð ˆS�#ˆXÑó"ðJ 3¨¡:ð ¸3ð À4ÈÈSÈÁ>ÐTXÑCXó ð@?%Ø%ð?%à˜D‘jð?%ð )ð?%ð *ð	?%ð
 -ð?%ð 	ˆ4�Zó?%ðD ‡�ØØ
$Ð	%ÙÐ+Ó,Ð-Ø#ð	 ó ð %�w—}’}¨TÐ?UÔVØ(˜7Ÿ=š=°ÐCbÔcØ,˜wŸ}š}°TÐGiÔjØ*˜WŸ]š]°4ÐEjÔkØ$�w—}’}¨TÐ?XÔYØ�—’ a¨A¸=ÔIØ"�W—]’]¨2°!¸ÐIcÔdØ'˜'Ÿ-š-ØØ]ôð $�g—m’m¨EÐ?]Ô^Ø#0 7§=¢=ØØ_ô$ñ )0Ð0AÓ(Bñ#ZØ
�‰*ðZà�D‰jðZð ˜‘*ðZð �d‘
ð	Zð
 �‰*ðZð ðZð ðZð �4‰ZðZð ðZð ˜D‘jðZð" &ò#ZóðZðz ‡�ØØ
$Ð	%ÙÐ+Ó,Ð-ð ó ð
 ñ )0Ð0AÓ(BÙ%+Øð tô&ñyØ
ðyà%ðyð ˜d™
òyó óðyðx+DØð+Dàð+Dð  ð+Dð 4ó	+Dð\?Ø%ð?à�4‰Zð?ð )ð?ð *ð	?ð
 -ð?ð 
ˆ#�Y�Ñó?ðD%Ø%ð%àð%ð )ð%ð *ð	%ð
 -ð%ð 
ˆ#�Yó%ðP ‡�ØØ
$Ð	%ÙÐ+Ó,Ð-Øàˆg�tÐ5Ñ6Ð7ðð ó ð (˜'Ÿ-š-°ÐBeÔfØ*˜WŸ]š]°4ÐEkÔlØ'˜'Ÿ-š-ØØ`ôð �—’ aÐ5QÐVWÔXØ"�W—]’]¨2Ð;UÐZ[Ð`cÔdÙ(/Ð0AÓ(BñQSØ�4‰ZðQSà�d‘
ðQSð �4‰ZðQSð ðQSð ðQSð &òQSóðQSðnlØ!ðlØ,4Ð5EÑ,Fðlà	ˆ#ˆtˆ)�_ólð ‡�ØØ
#Ð%?Ð	@ÙÐ+Ó,Ð-Ø2ð	 ó ð à*˜WŸ]š]ØØ5ôð )˜7Ÿ=š=ØØ3ôð &˜ŸšØØ.ôð (˜'Ÿ-š-ØØ0ôð (˜'Ÿ-š-Øð Tôð �—’ aÐ5QÐVWÔXØ"�W—]’]¨2Ð;KÐPQÐVZÔ[Ø(˜7Ÿ=š=ØðDôð
 %2 G§M¢MØðô%ñ )0Ð0AÓ(BñGk
Ø�d‘
ðk
ð
 �D‰jðk
ð �‰:ðk
ð �4‰Zðk
ð" �4‰Zð#k
ð* ð+k
ð, ð-k
ð. �D‰jð/k
ð8 "ð9k
ðF &ðGk
ðH %òIk
ó óðk
ð\ ‡�Ø%Ø
#Ð%?Ð	@ÙÐ+Ó,Ð-Ø2ð	 ó ð à*˜WŸ]š]ØØ5ôð )˜7Ÿ=š=ØØ3ôð &˜ŸšØØ.ôð (˜'Ÿ-š-ØØ0ôð (˜'Ÿ-š-Øð Tôð )˜7Ÿ=š=ØðDôð
 %2 G§M¢MØðô%ñ )0Ð0AÓ(BñCZ
Ø�d‘
ðZ
ð
 �D‰jðZ
ð �‰:ðZ
ð �4‰ZðZ
ð" �4‰Zð#Z
ð* �D‰jð+Z
ð4 "ð5Z
ðB &ðCZ
ðD %òEZ
ó óñZ
rL   