Add user login system with role-based access control: - Admin users see all data and can filter by any manager - Regular users only see records where ManagerName matches their username New components: - BIPUsersDAO: user authentication and management - SessionManager: singleton session state management - LoginDialog: modal login UI for app startup - init_users.sql: initial user setup script Permission enforcement: - Material validation tab: hide manager filter for non-admin, force filter by current user - Material type management: hide filter UI for non-admin, filter at database level - Window title and status bar display current user info Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
131 lines
3.4 KiB
Python
131 lines
3.4 KiB
Python
"""
|
|
Session Manager - Singleton pattern for managing authenticated user session
|
|
"""
|
|
from typing import Optional
|
|
|
|
|
|
class SessionManager:
|
|
"""
|
|
Singleton session manager to maintain authenticated user state
|
|
throughout the application lifecycle.
|
|
"""
|
|
|
|
_instance = None
|
|
|
|
def __new__(cls):
|
|
"""Implement singleton pattern"""
|
|
if cls._instance is None:
|
|
cls._instance = super(SessionManager, cls).__new__(cls)
|
|
cls._instance._initialized = False
|
|
return cls._instance
|
|
|
|
def __init__(self):
|
|
"""Initialize the session manager (only once)"""
|
|
if self._initialized:
|
|
return
|
|
|
|
self._current_user = None # {username, user_type}
|
|
self._initialized = True
|
|
|
|
@classmethod
|
|
def get_instance(cls) -> 'SessionManager':
|
|
"""
|
|
Get the singleton instance of SessionManager
|
|
|
|
Returns:
|
|
The singleton SessionManager instance
|
|
"""
|
|
if cls._instance is None:
|
|
cls._instance = cls()
|
|
return cls._instance
|
|
|
|
def login(self, username: str, password: str) -> bool:
|
|
"""
|
|
Authenticate and login a user
|
|
|
|
Args:
|
|
username: The username to authenticate
|
|
password: The password to verify
|
|
|
|
Returns:
|
|
True if login successful, False otherwise
|
|
"""
|
|
from db.bip_users_dao import BIPUsersDAO
|
|
|
|
dao = BIPUsersDAO()
|
|
user_info = dao.authenticate(username, password)
|
|
|
|
if user_info:
|
|
self._current_user = {
|
|
'username': user_info['username'],
|
|
'user_type': user_info['user_type']
|
|
}
|
|
return True
|
|
return False
|
|
|
|
def logout(self):
|
|
"""Logout the current user and clear session"""
|
|
self._current_user = None
|
|
|
|
def is_authenticated(self) -> bool:
|
|
"""
|
|
Check if a user is currently authenticated
|
|
|
|
Returns:
|
|
True if user is logged in, False otherwise
|
|
"""
|
|
return self._current_user is not None
|
|
|
|
def is_admin(self) -> bool:
|
|
"""
|
|
Check if the current user is an admin
|
|
|
|
Returns:
|
|
True if current user is admin, False otherwise
|
|
"""
|
|
if not self._current_user:
|
|
return False
|
|
return self._current_user.get('user_type') == 'Admin'
|
|
|
|
def is_guest(self) -> bool:
|
|
"""
|
|
Check if the current user is a guest
|
|
|
|
Returns:
|
|
True if current user is guest, False otherwise
|
|
"""
|
|
if not self._current_user:
|
|
return False
|
|
return self._current_user.get('user_type') == 'Guest'
|
|
|
|
def get_username(self) -> Optional[str]:
|
|
"""
|
|
Get the current username
|
|
|
|
Returns:
|
|
Current username if authenticated, None otherwise
|
|
"""
|
|
if not self._current_user:
|
|
return None
|
|
return self._current_user.get('username')
|
|
|
|
def get_user_type(self) -> Optional[str]:
|
|
"""
|
|
Get the current user type
|
|
|
|
Returns:
|
|
Current user type if authenticated, None otherwise
|
|
"""
|
|
if not self._current_user:
|
|
return None
|
|
return self._current_user.get('user_type')
|
|
|
|
def get_user_info(self) -> Optional[dict]:
|
|
"""
|
|
Get all current user information
|
|
|
|
Returns:
|
|
Dict with username and user_type if authenticated, None otherwise
|
|
"""
|
|
return self._current_user
|