feat: implement user authentication and permission-based data filtering
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>
This commit is contained in:
6
auth/__init__.py
Normal file
6
auth/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
"""
|
||||
Auth package for user authentication and session management
|
||||
"""
|
||||
from .session_manager import SessionManager
|
||||
|
||||
__all__ = ['SessionManager']
|
||||
130
auth/session_manager.py
Normal file
130
auth/session_manager.py
Normal file
@@ -0,0 +1,130 @@
|
||||
"""
|
||||
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
|
||||
Reference in New Issue
Block a user