2026-01-08 01:00:26 +10:30
|
|
|
"""Session service."""
|
2026-01-14 18:06:26 +10:30
|
|
|
from datetime import datetime, timezone
|
2026-03-01 16:50:27 +05:45
|
|
|
from gatehouse_app.models.user.session import Session
|
2026-04-28 20:54:15 +09:30
|
|
|
from gatehouse_app.utils.constants import SessionStatus, SessionType
|
2026-01-08 01:00:26 +10:30
|
|
|
|
|
|
|
|
|
|
|
|
|
class SessionService:
|
|
|
|
|
"""Service for session operations."""
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def get_active_session_by_token(token):
|
|
|
|
|
"""Get active session by token.
|
2026-04-26 18:12:37 +09:30
|
|
|
|
2026-01-08 01:00:26 +10:30
|
|
|
Args:
|
|
|
|
|
token: The session token string
|
2026-04-26 18:12:37 +09:30
|
|
|
|
2026-01-08 01:00:26 +10:30
|
|
|
Returns:
|
|
|
|
|
Session object if found and active, None otherwise
|
|
|
|
|
"""
|
2026-03-01 16:50:27 +05:45
|
|
|
from gatehouse_app.models.user.session import Session
|
2026-01-15 03:40:29 +10:30
|
|
|
from gatehouse_app.utils.constants import SessionStatus
|
2026-01-08 01:00:26 +10:30
|
|
|
return Session.query.filter_by(
|
|
|
|
|
token=token,
|
|
|
|
|
status=SessionStatus.ACTIVE,
|
|
|
|
|
deleted_at=None
|
2026-04-26 18:12:37 +09:30
|
|
|
).filter(
|
|
|
|
|
Session.expires_at > datetime.now(timezone.utc)
|
2026-01-08 01:00:26 +10:30
|
|
|
).first()
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
2026-04-28 20:54:15 +09:30
|
|
|
def get_owner_sessions(owner_type, owner_id, active_only=True):
|
|
|
|
|
"""Get all sessions for an owner (user or superadmin).
|
2026-01-08 01:00:26 +10:30
|
|
|
|
|
|
|
|
Args:
|
2026-04-28 20:54:15 +09:30
|
|
|
owner_type: SessionType.USER or SessionType.SUPERADMIN
|
|
|
|
|
owner_id: Owner ID
|
2026-01-08 01:00:26 +10:30
|
|
|
active_only: If True, only return active sessions
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
List of Session instances
|
|
|
|
|
"""
|
2026-04-28 20:54:15 +09:30
|
|
|
query = Session.query.filter_by(
|
|
|
|
|
owner_type=owner_type,
|
|
|
|
|
owner_id=owner_id,
|
|
|
|
|
deleted_at=None,
|
|
|
|
|
)
|
2026-01-08 01:00:26 +10:30
|
|
|
|
|
|
|
|
if active_only:
|
|
|
|
|
query = query.filter_by(status=SessionStatus.ACTIVE).filter(
|
2026-01-14 18:06:26 +10:30
|
|
|
Session.expires_at > datetime.now(timezone.utc)
|
2026-01-08 01:00:26 +10:30
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return query.all()
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
2026-04-28 20:54:15 +09:30
|
|
|
def get_user_sessions(user_id, active_only=True):
|
|
|
|
|
"""Get all sessions for a user.
|
2026-01-08 01:00:26 +10:30
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
user_id: User ID
|
2026-04-28 20:54:15 +09:30
|
|
|
active_only: If True, only return active sessions
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
List of Session instances
|
|
|
|
|
"""
|
|
|
|
|
return SessionService.get_owner_sessions(
|
|
|
|
|
SessionType.USER, user_id, active_only=active_only
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def get_superadmin_sessions(superadmin_id, active_only=True):
|
|
|
|
|
"""Get all sessions for a superadmin.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
superadmin_id: Superadmin ID
|
|
|
|
|
active_only: If True, only return active sessions
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
List of Session instances
|
2026-01-08 01:00:26 +10:30
|
|
|
"""
|
2026-04-28 20:54:15 +09:30
|
|
|
return SessionService.get_owner_sessions(
|
|
|
|
|
SessionType.SUPERADMIN, superadmin_id, active_only=active_only
|
|
|
|
|
)
|
2026-01-08 01:00:26 +10:30
|
|
|
|
2026-04-28 20:54:15 +09:30
|
|
|
@staticmethod
|
|
|
|
|
def revoke_owner_sessions(owner_type, owner_id, reason="Logged out from all devices"):
|
|
|
|
|
"""Revoke all active sessions for an owner.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
owner_type: SessionType.USER or SessionType.SUPERADMIN
|
|
|
|
|
owner_id: Owner ID
|
|
|
|
|
reason: Reason for revocation
|
|
|
|
|
"""
|
|
|
|
|
sessions = SessionService.get_owner_sessions(owner_type, owner_id, active_only=True)
|
2026-01-08 01:00:26 +10:30
|
|
|
for session in sessions:
|
|
|
|
|
session.revoke(reason=reason)
|
|
|
|
|
|
2026-04-28 20:54:15 +09:30
|
|
|
@staticmethod
|
|
|
|
|
def revoke_user_sessions(user_id, reason="User logged out from all devices"):
|
|
|
|
|
"""Revoke all active sessions for a user.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
user_id: User ID
|
|
|
|
|
reason: Reason for revocation
|
|
|
|
|
"""
|
|
|
|
|
SessionService.revoke_owner_sessions(SessionType.USER, user_id, reason=reason)
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def revoke_superadmin_sessions(superadmin_id, reason="Superadmin logged out"):
|
|
|
|
|
"""Revoke all active sessions for a superadmin.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
superadmin_id: Superadmin ID
|
|
|
|
|
reason: Reason for revocation
|
|
|
|
|
"""
|
|
|
|
|
SessionService.revoke_owner_sessions(SessionType.SUPERADMIN, superadmin_id, reason=reason)
|
|
|
|
|
|
2026-01-08 01:00:26 +10:30
|
|
|
@staticmethod
|
|
|
|
|
def cleanup_expired_sessions():
|
|
|
|
|
"""Clean up expired sessions."""
|
|
|
|
|
expired_sessions = Session.query.filter(
|
|
|
|
|
Session.status == SessionStatus.ACTIVE,
|
2026-01-14 18:06:26 +10:30
|
|
|
Session.expires_at < datetime.now(timezone.utc),
|
2026-01-08 01:00:26 +10:30
|
|
|
Session.deleted_at.is_(None),
|
|
|
|
|
).all()
|
|
|
|
|
|
|
|
|
|
for session in expired_sessions:
|
|
|
|
|
session.status = SessionStatus.EXPIRED
|
|
|
|
|
session.save()
|
|
|
|
|
|
|
|
|
|
return len(expired_sessions)
|