changes
This commit is contained in:
@@ -11,13 +11,128 @@ from sqlalchemy import text
|
||||
|
||||
def ensure_secondary_indexes(engine: Engine) -> None:
|
||||
statements = [
|
||||
# Files
|
||||
# Files - existing indexes
|
||||
"CREATE INDEX IF NOT EXISTS idx_files_status ON files(status)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_files_file_type ON files(file_type)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_files_empl_num ON files(empl_num)",
|
||||
# Ledger
|
||||
|
||||
# Files - new date indexes for performance
|
||||
"CREATE INDEX IF NOT EXISTS idx_files_opened ON files(opened)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_files_closed ON files(closed)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_files_id ON files(id)", # Foreign key to rolodex
|
||||
|
||||
# Ledger - existing indexes
|
||||
"CREATE INDEX IF NOT EXISTS idx_ledger_t_type ON ledger(t_type)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_ledger_empl_num ON ledger(empl_num)",
|
||||
|
||||
# Ledger - new indexes for performance
|
||||
"CREATE INDEX IF NOT EXISTS idx_ledger_date ON ledger(date)", # Critical for date range queries
|
||||
"CREATE INDEX IF NOT EXISTS idx_ledger_file_no ON ledger(file_no)", # Foreign key joins
|
||||
"CREATE INDEX IF NOT EXISTS idx_ledger_billed ON ledger(billed)", # Billing status queries
|
||||
|
||||
# Ledger - composite indexes for common query patterns
|
||||
"CREATE INDEX IF NOT EXISTS idx_ledger_date_type ON ledger(date, t_type)", # Date + transaction type
|
||||
"CREATE INDEX IF NOT EXISTS idx_ledger_date_billed ON ledger(date, billed)", # Recent unbilled entries
|
||||
"CREATE INDEX IF NOT EXISTS idx_ledger_file_date ON ledger(file_no, date)", # File-specific date ranges
|
||||
"CREATE INDEX IF NOT EXISTS idx_ledger_empl_date ON ledger(empl_num, date)", # Employee activity by date
|
||||
|
||||
# Phone - foreign key index
|
||||
"CREATE INDEX IF NOT EXISTS idx_phone_rolodex_id ON phone(rolodex_id)",
|
||||
|
||||
# Rolodex - additional indexes for search performance
|
||||
"CREATE INDEX IF NOT EXISTS idx_rolodex_abrev ON rolodex(abrev)", # State filtering
|
||||
"CREATE INDEX IF NOT EXISTS idx_rolodex_group ON rolodex(group)", # Group filtering
|
||||
"CREATE INDEX IF NOT EXISTS idx_rolodex_dob ON rolodex(dob)", # Date of birth queries
|
||||
|
||||
# Timer system indexes - for time tracking performance
|
||||
"CREATE INDEX IF NOT EXISTS idx_timers_user_id ON timers(user_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_timers_file_no ON timers(file_no)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_timers_customer_id ON timers(customer_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_timers_status ON timers(status)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_timers_started_at ON timers(started_at)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_timers_created_at ON timers(created_at)",
|
||||
|
||||
# Time entries indexes
|
||||
"CREATE INDEX IF NOT EXISTS idx_time_entries_user_id ON time_entries(user_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_time_entries_file_no ON time_entries(file_no)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_time_entries_customer_id ON time_entries(customer_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_time_entries_timer_id ON time_entries(timer_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_time_entries_entry_date ON time_entries(entry_date)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_time_entries_billed ON time_entries(billed)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_time_entries_created_at ON time_entries(created_at)",
|
||||
|
||||
# Timer sessions indexes
|
||||
"CREATE INDEX IF NOT EXISTS idx_timer_sessions_timer_id ON timer_sessions(timer_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_timer_sessions_started_at ON timer_sessions(started_at)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_timer_sessions_ended_at ON timer_sessions(ended_at)",
|
||||
|
||||
# Billing statement indexes - critical for financial reporting
|
||||
"CREATE INDEX IF NOT EXISTS idx_billing_statements_file_no ON billing_statements(file_no)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_billing_statements_customer_id ON billing_statements(customer_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_billing_statements_template_id ON billing_statements(template_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_billing_statements_statement_date ON billing_statements(statement_date)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_billing_statements_due_date ON billing_statements(due_date)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_billing_statements_status ON billing_statements(status)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_billing_statements_period_start ON billing_statements(period_start)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_billing_statements_period_end ON billing_statements(period_end)",
|
||||
|
||||
# Billing statement items indexes
|
||||
"CREATE INDEX IF NOT EXISTS idx_billing_statement_items_statement_id ON billing_statement_items(statement_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_billing_statement_items_ledger_id ON billing_statement_items(ledger_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_billing_statement_items_date ON billing_statement_items(date)",
|
||||
|
||||
# Statement payments indexes
|
||||
"CREATE INDEX IF NOT EXISTS idx_statement_payments_statement_id ON statement_payments(statement_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_statement_payments_payment_date ON statement_payments(payment_date)",
|
||||
|
||||
# File management indexes - for file history and tracking
|
||||
"CREATE INDEX IF NOT EXISTS idx_file_status_history_file_no ON file_status_history(file_no)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_file_status_history_change_date ON file_status_history(change_date)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_file_status_history_changed_by ON file_status_history(changed_by_user_id)",
|
||||
|
||||
# File transfer history indexes
|
||||
"CREATE INDEX IF NOT EXISTS idx_file_transfer_history_file_no ON file_transfer_history(file_no)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_file_transfer_history_transfer_date ON file_transfer_history(transfer_date)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_file_transfer_history_old_attorney ON file_transfer_history(old_attorney_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_file_transfer_history_new_attorney ON file_transfer_history(new_attorney_id)",
|
||||
|
||||
# File archive indexes
|
||||
"CREATE INDEX IF NOT EXISTS idx_file_archive_info_file_no ON file_archive_info(file_no)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_file_archive_info_archive_date ON file_archive_info(archive_date)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_file_archive_info_retention_date ON file_archive_info(retention_date)",
|
||||
|
||||
# File alerts indexes
|
||||
"CREATE INDEX IF NOT EXISTS idx_file_alerts_file_no ON file_alerts(file_no)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_file_alerts_alert_date ON file_alerts(alert_date)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_file_alerts_alert_type ON file_alerts(alert_type)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_file_alerts_is_active ON file_alerts(is_active)",
|
||||
|
||||
# File relationship indexes
|
||||
"CREATE INDEX IF NOT EXISTS idx_file_relationships_source ON file_relationships(source_file_no)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_file_relationships_target ON file_relationships(target_file_no)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_file_relationships_type ON file_relationships(relationship_type)",
|
||||
|
||||
# Deadline system indexes
|
||||
"CREATE INDEX IF NOT EXISTS idx_deadlines_file_no ON deadlines(file_no)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_deadlines_client_id ON deadlines(client_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_deadlines_deadline_date ON deadlines(deadline_date)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_deadlines_assigned_to_user ON deadlines(assigned_to_user_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_deadlines_status ON deadlines(status)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_deadlines_priority ON deadlines(priority)",
|
||||
|
||||
# Enhanced audit log indexes (if table exists)
|
||||
"CREATE INDEX IF NOT EXISTS idx_enhanced_audit_timestamp ON enhanced_audit_log(timestamp)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_enhanced_audit_user_id ON enhanced_audit_log(user_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_enhanced_audit_event_type ON enhanced_audit_log(event_type)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_enhanced_audit_severity ON enhanced_audit_log(severity)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_enhanced_audit_resource_type ON enhanced_audit_log(resource_type)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_enhanced_audit_source_ip ON enhanced_audit_log(source_ip)",
|
||||
|
||||
# Composite indexes for common query patterns
|
||||
"CREATE INDEX IF NOT EXISTS idx_time_entries_user_date ON time_entries(user_id, entry_date)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_file_alerts_active_date ON file_alerts(is_active, alert_date)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_billing_statements_status_date ON billing_statements(status, statement_date)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_deadlines_date_status ON deadlines(deadline_date, status)",
|
||||
]
|
||||
with engine.begin() as conn:
|
||||
for stmt in statements:
|
||||
|
||||
@@ -154,6 +154,24 @@ def ensure_schema_updates(engine: Engine) -> None:
|
||||
"users": {
|
||||
"is_approver": "BOOLEAN",
|
||||
},
|
||||
# Lookups: add legacy fields
|
||||
"group_lookups": {
|
||||
"title": "VARCHAR(200)",
|
||||
},
|
||||
"transaction_types": {
|
||||
"footer_code": "VARCHAR(45)",
|
||||
},
|
||||
# Employees: ensure extended columns from modernized exports
|
||||
"employees": {
|
||||
"first_name": "VARCHAR(50)",
|
||||
"last_name": "VARCHAR(100)",
|
||||
"title": "VARCHAR(100)",
|
||||
"initials": "VARCHAR(10)",
|
||||
"rate_per_hour": "FLOAT",
|
||||
"active": "BOOLEAN",
|
||||
"email": "VARCHAR(100)",
|
||||
"phone": "VARCHAR(20)",
|
||||
},
|
||||
}
|
||||
|
||||
with engine.begin() as conn:
|
||||
|
||||
144
app/database/session_schema.py
Normal file
144
app/database/session_schema.py
Normal file
@@ -0,0 +1,144 @@
|
||||
"""
|
||||
Database schema updates for session management
|
||||
"""
|
||||
from sqlalchemy import text
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.database.base import get_db, engine
|
||||
from app.models.sessions import UserSession, SessionActivity, SessionConfiguration, SessionSecurityEvent
|
||||
from app.utils.logging import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def create_session_tables():
|
||||
"""Create session management tables"""
|
||||
try:
|
||||
# Import and create all tables
|
||||
from app.models.sessions import UserSession
|
||||
UserSession.metadata.create_all(bind=engine)
|
||||
|
||||
logger.info("Session management tables created successfully")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to create session tables: {str(e)}")
|
||||
return False
|
||||
|
||||
|
||||
def create_session_indexes():
|
||||
"""Create additional indexes for session management performance"""
|
||||
|
||||
indexes = [
|
||||
# UserSession indexes
|
||||
"CREATE INDEX IF NOT EXISTS idx_user_sessions_user_status ON user_sessions(user_id, status)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_user_sessions_expires_status ON user_sessions(expires_at, status)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_user_sessions_last_activity ON user_sessions(last_activity)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_user_sessions_ip_address ON user_sessions(ip_address)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_user_sessions_risk_score ON user_sessions(risk_score)",
|
||||
|
||||
# SessionActivity indexes
|
||||
"CREATE INDEX IF NOT EXISTS idx_session_activities_user_timestamp ON session_activities(user_id, timestamp)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_session_activities_session_timestamp ON session_activities(session_id, timestamp)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_session_activities_activity_type ON session_activities(activity_type)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_session_activities_suspicious ON session_activities(is_suspicious)",
|
||||
|
||||
# SessionSecurityEvent indexes
|
||||
"CREATE INDEX IF NOT EXISTS idx_session_security_events_user_timestamp ON session_security_events(user_id, timestamp)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_session_security_events_severity ON session_security_events(severity)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_session_security_events_resolved ON session_security_events(resolved)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_session_security_events_event_type ON session_security_events(event_type)",
|
||||
|
||||
# SessionConfiguration indexes
|
||||
"CREATE INDEX IF NOT EXISTS idx_session_configurations_user_id ON session_configurations(user_id)"
|
||||
]
|
||||
|
||||
try:
|
||||
db = next(get_db())
|
||||
|
||||
for index_sql in indexes:
|
||||
try:
|
||||
db.execute(text(index_sql))
|
||||
logger.debug(f"Created index: {index_sql.split('idx_')[1].split(' ')[0] if 'idx_' in index_sql else 'unknown'}")
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to create index: {str(e)}")
|
||||
|
||||
db.commit()
|
||||
logger.info("Session management indexes created successfully")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to create session indexes: {str(e)}")
|
||||
return False
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def create_default_session_configuration():
|
||||
"""Create default global session configuration"""
|
||||
try:
|
||||
db = next(get_db())
|
||||
|
||||
# Check if global config already exists
|
||||
existing_config = db.query(SessionConfiguration).filter(
|
||||
SessionConfiguration.user_id.is_(None)
|
||||
).first()
|
||||
|
||||
if not existing_config:
|
||||
# Create default global configuration
|
||||
global_config = SessionConfiguration(
|
||||
user_id=None, # Global configuration
|
||||
max_concurrent_sessions=3,
|
||||
session_timeout_minutes=480, # 8 hours
|
||||
idle_timeout_minutes=60, # 1 hour
|
||||
require_session_renewal=True,
|
||||
renewal_interval_hours=24,
|
||||
force_logout_on_ip_change=False,
|
||||
suspicious_activity_threshold=5
|
||||
)
|
||||
|
||||
db.add(global_config)
|
||||
db.commit()
|
||||
|
||||
logger.info("Created default global session configuration")
|
||||
else:
|
||||
logger.info("Global session configuration already exists")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to create default session configuration: {str(e)}")
|
||||
return False
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def setup_session_management():
|
||||
"""Complete setup of session management system"""
|
||||
logger.info("Setting up session management system...")
|
||||
|
||||
success = True
|
||||
|
||||
# Create tables
|
||||
if not create_session_tables():
|
||||
success = False
|
||||
|
||||
# Create indexes
|
||||
if not create_session_indexes():
|
||||
success = False
|
||||
|
||||
# Create default configuration
|
||||
if not create_default_session_configuration():
|
||||
success = False
|
||||
|
||||
if success:
|
||||
logger.info("Session management system setup completed successfully")
|
||||
else:
|
||||
logger.error("Session management system setup completed with errors")
|
||||
|
||||
return success
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run setup when script is executed directly
|
||||
setup_session_management()
|
||||
Reference in New Issue
Block a user