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:
Quality App Developer
2026-01-28 00:46:59 +02:00
parent e6ff40184a
commit 8de85ca87f
18 changed files with 4194 additions and 167 deletions

View File

@@ -185,7 +185,6 @@ def create_user():
password = request.form.get('password', '').strip()
confirm_password = request.form.get('confirm_password', '').strip()
is_active = request.form.get('is_active') == 'on'
modules = request.form.getlist('modules')
# Validation
errors = []
@@ -202,8 +201,6 @@ def create_user():
errors.append("Passwords do not match")
if len(password) < 8:
errors.append("Password must be at least 8 characters")
if not modules:
errors.append("Select at least one module")
if errors:
conn = get_db()
@@ -251,13 +248,6 @@ def create_user():
(user_id, password_hash)
)
# Grant module access
for module in modules:
cursor.execute(
"INSERT IGNORE INTO user_modules (user_id, module_name) VALUES (%s, %s)",
(user_id, module)
)
conn.commit()
cursor.close()
@@ -311,11 +301,10 @@ def edit_user(user_id):
if request.method == 'GET':
cursor.close()
available_modules = ['quality', 'settings']
return render_template('modules/settings/user_form.html',
user=user,
roles=roles,
available_modules=available_modules,
available_modules=['quality', 'settings'],
user_modules=user_modules)
# Handle POST - Update user
@@ -326,7 +315,6 @@ def edit_user(user_id):
password = request.form.get('password', '').strip()
confirm_password = request.form.get('confirm_password', '').strip()
is_active = request.form.get('is_active') == 'on'
modules = request.form.getlist('modules')
# Validation
errors = []
@@ -339,16 +327,13 @@ def edit_user(user_id):
errors.append("Passwords do not match")
if password and len(password) < 8:
errors.append("Password must be at least 8 characters")
if not modules:
errors.append("Select at least one module")
if errors:
cursor.close()
available_modules = ['quality', 'settings']
return render_template('modules/settings/user_form.html',
user=user,
roles=roles,
available_modules=available_modules,
available_modules=['quality', 'settings'],
user_modules=user_modules,
error="; ".join(errors))
@@ -366,14 +351,6 @@ def edit_user(user_id):
(password_hash, user_id)
)
# Update module access
cursor.execute("DELETE FROM user_modules WHERE user_id = %s", (user_id,))
for module in modules:
cursor.execute(
"INSERT INTO user_modules (user_id, module_name) VALUES (%s, %s)",
(user_id, module)
)
conn.commit()
cursor.close()
@@ -381,11 +358,10 @@ def edit_user(user_id):
except Exception as e:
cursor.close()
available_modules = ['quality', 'settings']
return render_template('modules/settings/user_form.html',
user=user,
roles=roles,
available_modules=available_modules,
available_modules=['quality', 'settings'],
user_modules=user_modules,
error=f"Error updating user: {str(e)}")
@@ -862,6 +838,40 @@ def restore_database():
return jsonify({'error': str(e)}), 500
@settings_bp.route('/api/database/tables', methods=['GET'])
def get_database_tables():
"""Get list of all database tables (dynamically fetched)"""
if 'user_id' not in session:
return jsonify({'error': 'Unauthorized'}), 401
try:
conn = get_db()
cursor = conn.cursor()
# Get list of all tables with their row counts
cursor.execute("""
SELECT TABLE_NAME, TABLE_ROWS
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE()
ORDER BY TABLE_NAME
""")
tables = [{'name': row[0], 'rows': row[1] or 0} for row in cursor.fetchall()]
cursor.close()
return jsonify({
'success': True,
'tables': tables,
'count': len(tables)
})
except Exception as e:
return jsonify({
'success': False,
'error': str(e)
}), 500
@settings_bp.route('/api/database/truncate', methods=['POST'])
def truncate_table():
"""Truncate (clear) a database table"""