@@ -36,6 +36,8 @@ class User(db.Model):
3636 default = datetime .datetime .utcnow ,
3737 )
3838
39+ last_signed_in = db .Column (db .DateTime (), nullable = True )
40+
3941 __table_args__ = (
4042 db .Index ("ix_user_username" , func .lower (username ), unique = True ),
4143 db .Index ("ix_user_email" , func .lower (email ), unique = True ),
@@ -289,6 +291,7 @@ def __init__(self, user_id: int, ua: str, ip: str, device_id: Optional[str] = No
289291 self .user_agent = ua
290292 self .ip_address = ip
291293 self .device_id = device_id
294+ self .timestamp = datetime .datetime .now (tz = datetime .timezone .utc )
292295
293296 @staticmethod
294297 def add_record (user_id : int , req : request ) -> None :
@@ -300,4 +303,37 @@ def add_record(user_id: int, req: request) -> None:
300303 return
301304 lh = LoginHistory (user_id , ua , ip , device_id )
302305 db .session .add (lh )
306+
307+ # cache user last login
308+ User .query .filter_by (id = user_id ).update ({"last_signed_in" : lh .timestamp })
309+ db .session .commit ()
310+
311+ @staticmethod
312+ def get_users_last_signed_in (user_ids : list ) -> dict :
313+ """Get users last signed in dates.
314+ Result is also cached in User table for future use.
315+ """
316+ result = (
317+ db .session .query (
318+ LoginHistory .user_id ,
319+ func .max (LoginHistory .timestamp ).label ("last_signed_in" ),
320+ )
321+ .filter (LoginHistory .user_id .in_ (user_ids ))
322+ .group_by (LoginHistory .user_id )
323+ .all ()
324+ )
325+
326+ user_mapping = [
327+ {
328+ "id" : row .user_id , # user_id as PK in User table
329+ "last_signed_in" : row .last_signed_in ,
330+ }
331+ for row in result
332+ ]
333+ if not user_mapping :
334+ return {}
335+
336+ # cache users last signed in
337+ db .session .bulk_update_mappings (User , user_mapping )
303338 db .session .commit ()
339+ return {item ["id" ]: item ["last_signed_in" ] for item in user_mapping }
0 commit comments