@@ -311,90 +311,63 @@ async def wrapper(*args, request: Optional[Request] = None, **kwargs):
311311 status_code = 429 ,
312312 detail = f"Rate limit exceeded. Maximum { limit } requests per minute." ,
313313 )
314-
315314 rate_limit_storage [client_ip ].append (current_time )
316-
317315 # IMPORTANT: forward request to the real endpoint
318316 return await func_to_wrap (* args , request = request , ** kwargs )
319317
320318 return wrapper
321-
322319 return decorator
323320
324- def get_user_email (user ) -> str :
325- """Extract user email from JWT payload consistently.
321+
322+ def get_user_email (user : Union [str , dict , object ] = None ) -> str :
323+ """Return the user email from a JWT payload, user object, or string.
326324
327325 Args:
328- user: User object from JWT token (from get_current_user_with_permissions)
326+ user (Union[str, dict, object], optional): User object from JWT token
327+ (from get_current_user_with_permissions). Can be:
328+ - dict: representing JWT payload
329+ - object: with an `email` attribute
330+ - str: an email string
331+ - None: will return "unknown"
332+ Defaults to None.
329333
330334 Returns:
331- str: User email address
335+ str: User email address, or "unknown" if no email can be determined.
336+ - If `user` is a dict, returns `sub` if present, else `email`, else "unknown".
337+ - If `user` has an `email` attribute, returns that.
338+ - If `user` is a string, returns it.
339+ - If `user` is None, returns "unknown".
340+ - Otherwise, returns str(user).
332341
333342 Examples:
334- Test with dictionary user (JWT payload) with 'sub':
335- >>> from mcpgateway import admin
336- >>> user_dict = {'sub': '[email protected] ', 'iat': 1234567890} 337- >>> admin.get_user_email(user_dict)
343+ >>> get_user_email({'sub': '[email protected] '}) 338344339-
340- Test with dictionary user with 'email' field:
341- >>> user_dict = {'email': '[email protected] ', 'role': 'admin'} 342- >>> admin.get_user_email(user_dict)
345+ >>> get_user_email({'email': '[email protected] '}) 343346344-
345- Test with dictionary user with both 'sub' and 'email' (sub takes precedence):
346- >>> user_dict = {'sub': '[email protected] ', 'email': '[email protected] '} 347- >>> admin.get_user_email(user_dict)
347+ >>> get_user_email({'sub': '[email protected] ', 'email': '[email protected] '}) 348348349-
350- Test with dictionary user with no email fields:
351- >>> user_dict = {'username': 'dave', 'role': 'user'}
352- >>> admin.get_user_email(user_dict)
349+ >>> get_user_email({'username': 'dave'})
353350 'unknown'
354-
355- Test with user object having email attribute:
356351 >>> class MockUser:
357352 ... def __init__(self, email):
358353 ... self.email = email
359- >>> user_obj = MockUser('[email protected] ') 360- >>> admin.get_user_email(user_obj)
354+ >>> get_user_email(MockUser('[email protected] ')) 361355362-
363- Test with user object without email attribute:
364- >>> class BasicUser:
365- ... def __init__(self, name):
366- ... self.name = name
367- ... def __str__(self):
368- ... return self.name
369- >>> user_obj = BasicUser('frank')
370- >>> admin.get_user_email(user_obj)
371- 'frank'
372-
373- Test with None user:
374- >>> admin.get_user_email(None)
356+ >>> get_user_email(None)
375357 'unknown'
376-
377- Test with string user:
378- >>> admin.get_user_email('[email protected] ') 358+ >>> get_user_email('[email protected] ') 379359380-
381- Test with empty dictionary:
382- >>> admin.get_user_email({})
360+ >>> get_user_email({})
383361 'unknown'
384-
385- Test with non-string, non-dict, non-object values:
386- >>> admin.get_user_email(12345)
362+ >>> get_user_email(12345)
387363 '12345'
388364 """
389365 if isinstance (user , dict ):
390- # Standard JWT format - try 'sub' first, then 'email'
391366 return user .get ("sub" ) or user .get ("email" ) or "unknown"
392367
393368 if hasattr (user , "email" ):
394- # User object with email attribute
395369 return user .email
396370
397- # Fallback to string representation, but None becomes "unknown"
398371 if user is None :
399372 return "unknown"
400373
@@ -6135,7 +6108,8 @@ async def admin_add_gateway(request: Request, db: Session = Depends(get_db), use
61356108 LOGGER .info ("✅ Auto-detected OAuth configuration, setting auth_type='oauth'" )
61366109 elif oauth_config and auth_type_from_form :
61376110 LOGGER .info (f"✅ OAuth config present with explicit auth_type='{ auth_type_from_form } '" )
6138-
6111+
6112+
61396113 gateway = GatewayCreate (
61406114 name = str (form ["name" ]),
61416115 url = str (form ["url" ]),
0 commit comments