- Add Modules and UserModules database tables - Create home page with module selection grid - Implement per-user module assignment in user management - Add route guards for module access control - Refactor navigation: login -> home -> modules, admin console via button - Add Font Awesome icons
237 lines
9.1 KiB
Python
237 lines
9.1 KiB
Python
from flask import Blueprint, render_template, request, jsonify, session
|
|
from werkzeug.security import generate_password_hash
|
|
from db import query_db, execute_db
|
|
from utils import role_required
|
|
|
|
users_bp = Blueprint('users', __name__)
|
|
|
|
@users_bp.route('/settings/users')
|
|
@role_required('owner', 'admin')
|
|
def manage_users():
|
|
"""User management page"""
|
|
# Get all users
|
|
if session['role'] == 'owner':
|
|
# Owners can see everyone
|
|
users = query_db('SELECT * FROM Users ORDER BY role, full_name')
|
|
else:
|
|
# Admins can only see staff
|
|
users = query_db("SELECT * FROM Users WHERE role = 'staff' ORDER BY full_name")
|
|
|
|
# Get all active modules
|
|
modules = query_db('SELECT * FROM Modules WHERE is_active = 1 ORDER BY display_order')
|
|
|
|
return render_template('manage_users.html', users=users, modules=modules)
|
|
|
|
|
|
@users_bp.route('/settings/users/add', methods=['POST'])
|
|
@role_required('owner', 'admin')
|
|
def add_user():
|
|
"""Add a new user"""
|
|
data = request.get_json()
|
|
|
|
username = data.get('username', '').strip()
|
|
password = data.get('password', '')
|
|
first_name = data.get('first_name', '').strip()
|
|
last_name = data.get('last_name', '').strip()
|
|
email = data.get('email', '').strip()
|
|
role = data.get('role', 'staff')
|
|
branch = data.get('branch', 'Main')
|
|
|
|
# Validation
|
|
if not username or not password or not first_name or not last_name:
|
|
return jsonify({'success': False, 'message': 'Username, password, first name, and last name are required'})
|
|
|
|
# Admins can't create admins or owners
|
|
if session['role'] == 'admin' and role in ['admin', 'owner']:
|
|
return jsonify({'success': False, 'message': 'Permission denied: Admins can only create Staff users'})
|
|
|
|
# Check if username exists
|
|
existing = query_db('SELECT user_id FROM Users WHERE username = ?', [username], one=True)
|
|
if existing:
|
|
return jsonify({'success': False, 'message': 'Username already exists'})
|
|
|
|
# Create user
|
|
full_name = f"{first_name} {last_name}"
|
|
hashed_password = generate_password_hash(password)
|
|
|
|
try:
|
|
execute_db('''
|
|
INSERT INTO Users (username, password, full_name, role, branch, is_active)
|
|
VALUES (?, ?, ?, ?, ?, 1)
|
|
''', [username, hashed_password, full_name, role, branch])
|
|
|
|
return jsonify({'success': True, 'message': 'User created successfully'})
|
|
except Exception as e:
|
|
return jsonify({'success': False, 'message': f'Error creating user: {str(e)}'})
|
|
|
|
|
|
@users_bp.route('/settings/users/<int:user_id>', methods=['GET'])
|
|
@role_required('owner', 'admin')
|
|
def get_user(user_id):
|
|
"""Get user details"""
|
|
user = query_db('SELECT * FROM Users WHERE user_id = ?', [user_id], one=True)
|
|
|
|
if not user:
|
|
return jsonify({'success': False, 'message': 'User not found'})
|
|
|
|
# Admins can't view other admins or owners
|
|
if session['role'] == 'admin' and user['role'] in ['admin', 'owner']:
|
|
return jsonify({'success': False, 'message': 'Permission denied'})
|
|
|
|
# Split full name
|
|
name_parts = user['full_name'].split(' ', 1)
|
|
first_name = name_parts[0] if len(name_parts) > 0 else ''
|
|
last_name = name_parts[1] if len(name_parts) > 1 else ''
|
|
|
|
# Get email, handle None
|
|
email = user['email'] if user['email'] else ''
|
|
|
|
return jsonify({
|
|
'success': True,
|
|
'user': {
|
|
'user_id': user['user_id'],
|
|
'username': user['username'],
|
|
'first_name': first_name,
|
|
'last_name': last_name,
|
|
'email': email,
|
|
'role': user['role'],
|
|
'branch': user['branch'],
|
|
'is_active': user['is_active']
|
|
}
|
|
})
|
|
|
|
|
|
@users_bp.route('/settings/users/<int:user_id>/update', methods=['POST'])
|
|
@role_required('owner', 'admin')
|
|
def update_user(user_id):
|
|
"""Update user details"""
|
|
data = request.get_json()
|
|
|
|
# Get existing user
|
|
user = query_db('SELECT * FROM Users WHERE user_id = ?', [user_id], one=True)
|
|
|
|
if not user:
|
|
return jsonify({'success': False, 'message': 'User not found'})
|
|
|
|
# Admins can't edit other admins or owners
|
|
if session['role'] == 'admin' and user['role'] in ['admin', 'owner']:
|
|
return jsonify({'success': False, 'message': 'Permission denied'})
|
|
|
|
# Can't edit yourself to change your own role or deactivate
|
|
if user_id == session['user_id']:
|
|
if data.get('role') != user['role']:
|
|
return jsonify({'success': False, 'message': 'Cannot change your own role'})
|
|
if data.get('is_active') == 0:
|
|
return jsonify({'success': False, 'message': 'Cannot deactivate yourself'})
|
|
|
|
# Build update
|
|
username = data.get('username', '').strip()
|
|
first_name = data.get('first_name', '').strip()
|
|
last_name = data.get('last_name', '').strip()
|
|
email = data.get('email', '').strip()
|
|
role = data.get('role', user['role'])
|
|
branch = data.get('branch', user['branch'])
|
|
is_active = data.get('is_active', user['is_active'])
|
|
password = data.get('password', '').strip()
|
|
|
|
if not username or not first_name or not last_name:
|
|
return jsonify({'success': False, 'message': 'Username, first name, and last name are required'})
|
|
|
|
# Check if username is taken by another user
|
|
if username != user['username']:
|
|
existing = query_db('SELECT user_id FROM Users WHERE username = ? AND user_id != ?', [username, user_id], one=True)
|
|
if existing:
|
|
return jsonify({'success': False, 'message': 'Username already taken'})
|
|
|
|
# Admins can't change role to admin or owner
|
|
if session['role'] == 'admin' and role in ['admin', 'owner']:
|
|
return jsonify({'success': False, 'message': 'Permission denied: Cannot assign Admin or Owner role'})
|
|
|
|
full_name = f"{first_name} {last_name}"
|
|
|
|
try:
|
|
if password:
|
|
# Update with new password
|
|
hashed_password = generate_password_hash(password)
|
|
execute_db('''
|
|
UPDATE Users
|
|
SET username = ?, full_name = ?, email = ?, role = ?, branch = ?, is_active = ?, password = ?
|
|
WHERE user_id = ?
|
|
''', [username, full_name, email, role, branch, is_active, hashed_password, user_id])
|
|
else:
|
|
# Update without changing password
|
|
execute_db('''
|
|
UPDATE Users
|
|
SET username = ?, full_name = ?, email = ?, role = ?, branch = ?, is_active = ?
|
|
WHERE user_id = ?
|
|
''', [username, full_name, email, role, branch, is_active, user_id])
|
|
|
|
return jsonify({'success': True, 'message': 'User updated successfully'})
|
|
except Exception as e:
|
|
return jsonify({'success': False, 'message': f'Error updating user: {str(e)}'})
|
|
|
|
|
|
@users_bp.route('/settings/users/<int:user_id>/delete', methods=['POST'])
|
|
@role_required('owner', 'admin')
|
|
def delete_user(user_id):
|
|
"""Delete (deactivate) a user"""
|
|
# Get user
|
|
user = query_db('SELECT * FROM Users WHERE user_id = ?', [user_id], one=True)
|
|
|
|
if not user:
|
|
return jsonify({'success': False, 'message': 'User not found'})
|
|
|
|
# Admins can't delete other admins or owners
|
|
if session['role'] == 'admin' and user['role'] in ['admin', 'owner']:
|
|
return jsonify({'success': False, 'message': 'Permission denied'})
|
|
|
|
# Can't delete yourself
|
|
if user_id == session['user_id']:
|
|
return jsonify({'success': False, 'message': 'Cannot delete yourself'})
|
|
|
|
# Soft delete (deactivate)
|
|
try:
|
|
execute_db('UPDATE Users SET is_active = 0 WHERE user_id = ?', [user_id])
|
|
return jsonify({'success': True, 'message': 'User deleted successfully'})
|
|
except Exception as e:
|
|
return jsonify({'success': False, 'message': f'Error deleting user: {str(e)}'})
|
|
|
|
|
|
@users_bp.route('/settings/users/<int:user_id>/modules', methods=['GET'])
|
|
@role_required('owner', 'admin')
|
|
def get_user_modules(user_id):
|
|
"""Get modules assigned to a user"""
|
|
modules = query_db('''
|
|
SELECT module_id FROM UserModules WHERE user_id = ?
|
|
''', [user_id])
|
|
|
|
module_ids = [m['module_id'] for m in modules]
|
|
return jsonify({'success': True, 'module_ids': module_ids})
|
|
|
|
|
|
@users_bp.route('/settings/users/<int:user_id>/modules', methods=['POST'])
|
|
@role_required('owner', 'admin')
|
|
def update_user_modules(user_id):
|
|
"""Update modules assigned to a user"""
|
|
data = request.get_json()
|
|
module_ids = data.get('module_ids', [])
|
|
|
|
# Verify user exists
|
|
user = query_db('SELECT user_id FROM Users WHERE user_id = ?', [user_id], one=True)
|
|
if not user:
|
|
return jsonify({'success': False, 'message': 'User not found'})
|
|
|
|
try:
|
|
# Remove all current assignments
|
|
execute_db('DELETE FROM UserModules WHERE user_id = ?', [user_id])
|
|
|
|
# Add new assignments
|
|
for module_id in module_ids:
|
|
execute_db('''
|
|
INSERT INTO UserModules (user_id, module_id, granted_by)
|
|
VALUES (?, ?, ?)
|
|
''', [user_id, module_id, session['user_id']])
|
|
|
|
return jsonify({'success': True, 'message': 'Modules updated'})
|
|
except Exception as e:
|
|
return jsonify({'success': False, 'message': str(e)}) |