1+ from datetime import datetime , timezone
12from typing import Any , Dict , Generic , List , Literal , Optional , Union , cast , overload
23
34from httpx import Response
2021)
2122from weaviate .util import _decode_json_response_dict , escape_string
2223
24+ # Go's zero time value, returned by the server when a timestamp is not set
25+ _GO_ZERO_TIME = datetime (1 , 1 , 1 , 0 , 0 , tzinfo = timezone .utc )
26+
27+
28+ def _parse_last_used_at (value : Optional [str ]) -> Optional [datetime ]:
29+ if value is None :
30+ return None
31+ dt = datetime .fromisoformat (value .replace ("Z" , "+00:00" ))
32+ return None if dt == _GO_ZERO_TIME else dt
33+
2334
2435class _BaseExecutor (Generic [ConnectionType ]):
2536 def __init__ (self , connection : ConnectionType ):
@@ -451,35 +462,51 @@ def resp(res: Response) -> bool:
451462 status_codes = _ExpectedStatusCodes (ok_in = [200 , 409 ], error = "Deactivate user" ),
452463 )
453464
454- def get (self , * , user_id : str ) -> executor .Result [Optional [UserDB ]]:
465+ def get (
466+ self , * , user_id : str , include_last_used_time : bool = False
467+ ) -> executor .Result [Optional [UserDB ]]:
455468 """Get all information about an user.
456469
457470 Args:
458471 user_id: The id of the user.
472+ include_last_used_time: If True, the last used time of the user will be included.
459473 """
460474
461475 def resp (res : Response ) -> Optional [UserDB ]:
462476 if res .status_code == 404 :
463477 return None
464478 parsed = _decode_json_response_dict (res , "Get user" )
465479 assert parsed is not None
480+ created_at = parsed .get ("createdAt" )
466481 return UserDB (
467482 user_id = parsed ["userId" ],
468483 role_names = parsed ["roles" ],
469484 active = parsed ["active" ],
470485 user_type = UserTypes (parsed ["dbUserType" ]),
486+ created_at = (
487+ datetime .fromisoformat (created_at .replace ("Z" , "+00:00" ))
488+ if created_at is not None
489+ else None
490+ ),
491+ last_used_time = _parse_last_used_at (parsed .get ("lastUsedAt" )),
492+ api_key_first_letters = parsed .get ("apiKeyFirstLetters" ),
471493 )
472494
473495 return executor .execute (
474496 response_callback = resp ,
475497 method = self ._connection .get ,
476498 path = f"/users/db/{ user_id } " ,
499+ params = {"includeLastUsedTime" : include_last_used_time },
477500 error_msg = f"Could not get user '{ user_id } '" ,
478501 status_codes = _ExpectedStatusCodes (ok_in = [200 , 404 ], error = "get user" ),
479502 )
480503
481- def list_all (self ) -> executor .Result [List [UserDB ]]:
482- """List all DB users."""
504+ def list_all (self , * , include_last_used_time : bool = False ) -> executor .Result [List [UserDB ]]:
505+ """List all DB users.
506+
507+ Args:
508+ include_last_used_time: If True, the last used time of each user will be included.
509+ """
483510
484511 def resp (res : Response ) -> List [UserDB ]:
485512 parsed = _decode_json_response_dict (res , "Get user" )
@@ -490,6 +517,13 @@ def resp(res: Response) -> List[UserDB]:
490517 role_names = user ["roles" ],
491518 active = user ["active" ],
492519 user_type = UserTypes (user ["dbUserType" ]),
520+ created_at = (
521+ datetime .fromisoformat (ca .replace ("Z" , "+00:00" ))
522+ if (ca := user .get ("createdAt" )) is not None
523+ else None
524+ ),
525+ last_used_time = _parse_last_used_at (user .get ("lastUsedAt" )),
526+ api_key_first_letters = user .get ("apiKeyFirstLetters" ),
493527 )
494528 for user in cast (List [WeaviateDBUserRoleNames ], parsed )
495529 ]
@@ -498,6 +532,7 @@ def resp(res: Response) -> List[UserDB]:
498532 response_callback = resp ,
499533 method = self ._connection .get ,
500534 path = "/users/db" ,
535+ params = {"includeLastUsedTime" : include_last_used_time },
501536 error_msg = "Could not list all users" ,
502537 status_codes = _ExpectedStatusCodes (ok_in = [200 ], error = "list all users" ),
503538 )
0 commit comments