SQLite and JSON toggle support added
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
+35
-87
@@ -3,33 +3,14 @@ User Management Blueprint
|
||||
Handles user CRUD operations
|
||||
"""
|
||||
from flask import Blueprint, render_template, request, jsonify, send_file, session
|
||||
from werkzeug.security import generate_password_hash, check_password_hash
|
||||
from werkzeug.security import check_password_hash
|
||||
from blueprints.auth import login_required, can_user, get_current_user
|
||||
import data_access as da
|
||||
from io import BytesIO
|
||||
import json
|
||||
import os
|
||||
|
||||
users_bp = Blueprint('users', __name__, url_prefix='/users')
|
||||
|
||||
# Path to users file
|
||||
USERS_FILE = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'data', 'users.json')
|
||||
|
||||
def load_users():
|
||||
"""Load users from JSON file"""
|
||||
if os.path.exists(USERS_FILE):
|
||||
try:
|
||||
with open(USERS_FILE, 'r') as f:
|
||||
return json.load(f)
|
||||
except:
|
||||
return []
|
||||
return []
|
||||
|
||||
def save_users(users):
|
||||
"""Save users to JSON file"""
|
||||
os.makedirs(os.path.dirname(USERS_FILE), exist_ok=True)
|
||||
with open(USERS_FILE, 'w') as f:
|
||||
json.dump(users, f, indent=2)
|
||||
|
||||
def permission_required(permission):
|
||||
"""Decorator to require specific permission"""
|
||||
from functools import wraps
|
||||
@@ -52,15 +33,14 @@ def user_manager():
|
||||
"""Serve the user management page"""
|
||||
if not can_user('manage_users'):
|
||||
return "<h1>403 - Permission Denied</h1><p>You don't have permission to manage users.</p>", 403
|
||||
current_user_id = session.get('user_id', -1)
|
||||
return render_template('user_manager.html', current_user_id=current_user_id)
|
||||
return render_template('user_manager.html')
|
||||
|
||||
@users_bp.route('/api', methods=['GET'])
|
||||
@login_required
|
||||
@permission_required('manage_users')
|
||||
def get_users():
|
||||
"""Get all users"""
|
||||
users = load_users()
|
||||
users = da.get_all_users()
|
||||
return jsonify({
|
||||
'status': 'success',
|
||||
'users': users
|
||||
@@ -81,40 +61,16 @@ def add_user():
|
||||
'message': 'Username, password, and default location are required'
|
||||
}), 400
|
||||
|
||||
users = load_users()
|
||||
# Create user via data access layer
|
||||
new_user = da.create_user(data)
|
||||
|
||||
# Check if username already exists
|
||||
if any(user['username'] == data['username'] for user in users):
|
||||
if not new_user:
|
||||
return jsonify({
|
||||
'status': 'error',
|
||||
'message': 'Username already exists'
|
||||
}), 400
|
||||
|
||||
# Hash the password
|
||||
hashed_password = generate_password_hash(data['password'], method='pbkdf2:sha256')
|
||||
|
||||
# Get location settings
|
||||
location_settings = data.get('locationSettings', {})
|
||||
default_location = data['defaultLocation']
|
||||
|
||||
# Ensure default location is accessible
|
||||
if default_location not in location_settings:
|
||||
location_settings[default_location] = {}
|
||||
location_settings[default_location]['accessible'] = True
|
||||
|
||||
# Create new user
|
||||
new_user = {
|
||||
'username': data['username'],
|
||||
'password': hashed_password,
|
||||
'defaultLocation': default_location,
|
||||
'locationSettings': location_settings,
|
||||
'permissions': data.get('permissions', {}),
|
||||
'active': data.get('active', True)
|
||||
}
|
||||
|
||||
users.append(new_user)
|
||||
save_users(users)
|
||||
|
||||
users = da.get_all_users()
|
||||
return jsonify({
|
||||
'status': 'success',
|
||||
'message': 'User added successfully',
|
||||
@@ -122,28 +78,25 @@ def add_user():
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
da.rollback()
|
||||
return jsonify({
|
||||
'status': 'error',
|
||||
'message': str(e)
|
||||
}), 500
|
||||
|
||||
@users_bp.route('/api/<int:user_index>', methods=['DELETE'])
|
||||
@users_bp.route('/api/<int:user_id>', methods=['DELETE'])
|
||||
@login_required
|
||||
@permission_required('manage_users')
|
||||
def delete_user(user_index):
|
||||
"""Delete a specific user by index"""
|
||||
def delete_user(user_id):
|
||||
"""Delete a specific user by ID"""
|
||||
try:
|
||||
users = load_users()
|
||||
|
||||
if user_index < 0 or user_index >= len(users):
|
||||
if not da.delete_user(user_id):
|
||||
return jsonify({
|
||||
'status': 'error',
|
||||
'message': 'Invalid user index'
|
||||
}), 400
|
||||
|
||||
users.pop(user_index)
|
||||
save_users(users)
|
||||
'message': 'User not found'
|
||||
}), 404
|
||||
|
||||
users = da.get_all_users()
|
||||
return jsonify({
|
||||
'status': 'success',
|
||||
'message': 'User deleted successfully',
|
||||
@@ -151,29 +104,28 @@ def delete_user(user_index):
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
da.rollback()
|
||||
return jsonify({
|
||||
'status': 'error',
|
||||
'message': str(e)
|
||||
}), 500
|
||||
|
||||
@users_bp.route('/api/<int:user_index>/active', methods=['PATCH'])
|
||||
@users_bp.route('/api/<int:user_id>/active', methods=['PATCH'])
|
||||
@login_required
|
||||
@permission_required('manage_users')
|
||||
def toggle_user_active(user_index):
|
||||
def toggle_user_active(user_id):
|
||||
"""Toggle user active status"""
|
||||
try:
|
||||
data = request.json
|
||||
users = load_users()
|
||||
user = da.toggle_user_active(user_id, data.get('active', True))
|
||||
|
||||
if user_index < 0 or user_index >= len(users):
|
||||
if not user:
|
||||
return jsonify({
|
||||
'status': 'error',
|
||||
'message': 'Invalid user index'
|
||||
}), 400
|
||||
|
||||
users[user_index]['active'] = data.get('active', True)
|
||||
save_users(users)
|
||||
'message': 'User not found'
|
||||
}), 404
|
||||
|
||||
users = da.get_all_users()
|
||||
return jsonify({
|
||||
'status': 'success',
|
||||
'message': 'User status updated',
|
||||
@@ -181,15 +133,16 @@ def toggle_user_active(user_index):
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
da.rollback()
|
||||
return jsonify({
|
||||
'status': 'error',
|
||||
'message': str(e)
|
||||
}), 500
|
||||
|
||||
@users_bp.route('/api/<int:user_index>/change-password', methods=['POST'])
|
||||
@users_bp.route('/api/<int:user_id>/change-password', methods=['POST'])
|
||||
@login_required
|
||||
@permission_required('manage_users')
|
||||
def change_user_password(user_index):
|
||||
def change_user_password(user_id):
|
||||
"""Change a user's password with current user verification"""
|
||||
try:
|
||||
data = request.json
|
||||
@@ -222,26 +175,21 @@ def change_user_password(user_index):
|
||||
'message': 'Your password is incorrect. Password change denied for security reasons.'
|
||||
}), 403
|
||||
|
||||
# Load users and validate index
|
||||
users = load_users()
|
||||
if user_index < 0 or user_index >= len(users):
|
||||
# Update password via data access layer
|
||||
updated_user = da.change_user_password(user_id, new_password)
|
||||
if not updated_user:
|
||||
return jsonify({
|
||||
'status': 'error',
|
||||
'message': 'Invalid user index'
|
||||
}), 400
|
||||
|
||||
# Update password
|
||||
hashed_password = generate_password_hash(new_password, method='pbkdf2:sha256')
|
||||
target_username = users[user_index]['username']
|
||||
users[user_index]['password'] = hashed_password
|
||||
save_users(users)
|
||||
'message': 'User not found'
|
||||
}), 404
|
||||
|
||||
return jsonify({
|
||||
'status': 'success',
|
||||
'message': f'Password changed successfully for user "{target_username}"'
|
||||
'message': f'Password changed successfully for user "{updated_user["username"]}"'
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
da.rollback()
|
||||
return jsonify({
|
||||
'status': 'error',
|
||||
'message': str(e)
|
||||
@@ -253,7 +201,7 @@ def change_user_password(user_index):
|
||||
def download_users():
|
||||
"""Download users as JSON file"""
|
||||
try:
|
||||
users = load_users()
|
||||
users = da.get_all_users()
|
||||
|
||||
if not users:
|
||||
return jsonify({
|
||||
|
||||
Reference in New Issue
Block a user