feat: Implement warehouse module roles with auto-schema repair and remove module access section
- Add SchemaVerifier class for automatic database schema verification and repair - Implement warehouse_manager (Level 75) and warehouse_worker (Level 35) roles - Add zone-based access control for warehouse workers - Implement worker-manager binding system with zone filtering - Add comprehensive database auto-repair on Docker initialization - Remove Module Access section from user form (role-based access only) - Add autocomplete attributes to password fields for better UX - Include detailed documentation for warehouse implementation - Update initialize_db.py with schema verification as Step 0
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
"""
|
||||
Comprehensive Database Initialization Script
|
||||
Creates all required tables and initializes default data
|
||||
Includes schema verification to check existing databases for correctness
|
||||
This script should be run once when the application starts
|
||||
"""
|
||||
|
||||
@@ -11,6 +12,7 @@ import sys
|
||||
import logging
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
from app.db_schema_verifier import SchemaVerifier
|
||||
|
||||
# Setup logging
|
||||
logging.basicConfig(
|
||||
@@ -58,6 +60,66 @@ def execute_sql(conn, sql, params=None, description=""):
|
||||
return False
|
||||
|
||||
|
||||
def check_and_repair_database():
|
||||
"""
|
||||
Check existing database for correct structure
|
||||
Repair any missing tables, columns, or reference data
|
||||
"""
|
||||
logger.info("Step 0: Checking existing database structure...")
|
||||
|
||||
try:
|
||||
# First check if database exists
|
||||
conn = pymysql.connect(
|
||||
host=DB_HOST,
|
||||
port=DB_PORT,
|
||||
user=DB_USER,
|
||||
password=DB_PASSWORD
|
||||
)
|
||||
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(f"SHOW DATABASES LIKE %s", (DB_NAME,))
|
||||
|
||||
if not cursor.fetchone():
|
||||
# Database doesn't exist, skip verification
|
||||
logger.info(" ℹ Database doesn't exist yet, skipping structure check")
|
||||
conn.close()
|
||||
return True
|
||||
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
# Database exists, now connect to it and verify/repair structure
|
||||
conn = pymysql.connect(
|
||||
host=DB_HOST,
|
||||
port=DB_PORT,
|
||||
user=DB_USER,
|
||||
password=DB_PASSWORD,
|
||||
database=DB_NAME
|
||||
)
|
||||
|
||||
# Run schema verification and repair
|
||||
verifier = SchemaVerifier(conn)
|
||||
success, summary = verifier.verify_and_repair()
|
||||
|
||||
# Log the summary
|
||||
for line in summary.split('\n'):
|
||||
if line.strip():
|
||||
logger.info(f" {line}")
|
||||
|
||||
conn.close()
|
||||
return success
|
||||
|
||||
except pymysql.Error as e:
|
||||
if "Unknown database" in str(e):
|
||||
logger.info(" ℹ Database doesn't exist yet, skipping structure check")
|
||||
return True
|
||||
logger.error(f"✗ Database check failed: {e}")
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.error(f"✗ Database check error: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def create_database():
|
||||
"""Create the database if it doesn't exist"""
|
||||
logger.info("Step 1: Creating database...")
|
||||
@@ -229,6 +291,23 @@ def create_tables():
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
""", description="Table 'user_permissions'")
|
||||
|
||||
# Worker-Manager bindings (for warehouse module hierarchy)
|
||||
execute_sql(conn, """
|
||||
CREATE TABLE IF NOT EXISTS worker_manager_bindings (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
manager_id INT NOT NULL,
|
||||
worker_id INT NOT NULL,
|
||||
warehouse_zone VARCHAR(100),
|
||||
is_active TINYINT(1) DEFAULT 1,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY unique_binding (manager_id, worker_id),
|
||||
FOREIGN KEY (manager_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (worker_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
CHECK (manager_id != worker_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
""", description="Table 'worker_manager_bindings'")
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
logger.info("✓ All tables created successfully")
|
||||
@@ -257,8 +336,10 @@ def insert_default_data():
|
||||
roles = [
|
||||
('superadmin', 'Super Administrator - Full system access', 100),
|
||||
('admin', 'Administrator - Administrative access', 90),
|
||||
('manager', 'Manager - Full access to assigned modules', 70),
|
||||
('worker', 'Worker - Limited access', 50),
|
||||
('manager', 'Manager - Quality - Full access to assigned modules', 70),
|
||||
('warehouse_manager', 'Manager - Warehouse - Full warehouse module access', 75),
|
||||
('worker', 'Worker - Quality - Limited access', 50),
|
||||
('warehouse_worker', 'Worker - Warehouse - Input-only warehouse access', 35),
|
||||
]
|
||||
|
||||
logger.info(" Creating roles...")
|
||||
@@ -407,6 +488,7 @@ def main():
|
||||
logger.info(f"Target: {DB_USER}@{DB_HOST}:{DB_PORT}/{DB_NAME}\n")
|
||||
|
||||
steps = [
|
||||
("Check/repair existing database", check_and_repair_database),
|
||||
("Create database", create_database),
|
||||
("Create tables", create_tables),
|
||||
("Insert default data", insert_default_data),
|
||||
|
||||
Reference in New Issue
Block a user