0632aa22e1
Co-authored-by: Copilot <copilot@github.com>
224 lines
7.0 KiB
Python
224 lines
7.0 KiB
Python
"""
|
|
Authentication Blueprint
|
|
Handles login, logout, and session management
|
|
"""
|
|
from flask import Blueprint, render_template, request, jsonify, session, redirect, url_for
|
|
from werkzeug.security import check_password_hash
|
|
from functools import wraps
|
|
import data_access as da
|
|
import config
|
|
|
|
auth_bp = Blueprint('auth', __name__)
|
|
|
|
def login_required(f):
|
|
"""Decorator to require login for routes"""
|
|
@wraps(f)
|
|
def decorated_function(*args, **kwargs):
|
|
if 'username' not in session:
|
|
return redirect(url_for('auth.login_page'))
|
|
|
|
# Check if user is active
|
|
user = da.get_user_by_username(session['username'])
|
|
if not user or not user.get('active', True):
|
|
session.clear()
|
|
return redirect(url_for('auth.login_page', message='Account is inactive'))
|
|
|
|
return f(*args, **kwargs)
|
|
return decorated_function
|
|
|
|
def get_current_user():
|
|
"""Get the currently logged in user"""
|
|
if 'username' not in session:
|
|
return None
|
|
|
|
return da.get_user_by_username(session['username'])
|
|
|
|
def can_user(permission, location=None):
|
|
"""
|
|
Check if current user has a specific permission.
|
|
|
|
Args:
|
|
permission (str): Permission name (e.g., 'manage_users')
|
|
location (str, optional): Check permission for specific location
|
|
|
|
Returns:
|
|
bool: True if user has permission
|
|
"""
|
|
user = get_current_user()
|
|
if not user:
|
|
return False
|
|
|
|
if not user.get('active', True):
|
|
return False
|
|
|
|
# Check global permissions
|
|
global_permissions = user.get('permissions', {})
|
|
if permission in global_permissions:
|
|
return global_permissions[permission] is True
|
|
|
|
if location == 'global':
|
|
return False
|
|
|
|
# Check location-specific permissions
|
|
check_location = location if location else session.get('currentLocation')
|
|
if not check_location:
|
|
return False
|
|
|
|
location_settings = user.get('locationSettings', {})
|
|
if check_location in location_settings:
|
|
loc_permissions = location_settings[check_location].get('permissions', {})
|
|
if permission in loc_permissions:
|
|
return loc_permissions[permission] is True
|
|
|
|
return False
|
|
|
|
# Routes
|
|
@auth_bp.route('/login')
|
|
def login_page():
|
|
"""Serve the login page"""
|
|
if 'username' in session:
|
|
return redirect(url_for('home'))
|
|
return render_template('login.html')
|
|
|
|
@auth_bp.route('/select-location')
|
|
def select_location_page():
|
|
"""Serve the location selection page"""
|
|
if 'username' not in session:
|
|
return redirect(url_for('auth.login_page'))
|
|
return render_template('select_location.html')
|
|
|
|
@auth_bp.route('/api/login', methods=['POST'])
|
|
def login():
|
|
"""Authenticate user and create session"""
|
|
try:
|
|
data = request.json
|
|
username = data.get('username')
|
|
password = data.get('password')
|
|
|
|
if not username or not password:
|
|
return jsonify({
|
|
'status': 'error',
|
|
'message': 'Username and password are required'
|
|
}), 400
|
|
|
|
# Find user by username
|
|
user = da.get_user_by_username(username)
|
|
|
|
if not user:
|
|
return jsonify({
|
|
'status': 'error',
|
|
'message': 'Invalid username or password'
|
|
}), 401
|
|
|
|
# Check if user is active
|
|
if not user.get('active', True):
|
|
return jsonify({
|
|
'status': 'error',
|
|
'message': 'Account is inactive. Please contact an administrator.'
|
|
}), 403
|
|
|
|
# Verify password
|
|
if not check_password_hash(user['password'], password):
|
|
return jsonify({
|
|
'status': 'error',
|
|
'message': 'Invalid username or password'
|
|
}), 401
|
|
|
|
# Create session
|
|
session['username'] = user['username']
|
|
session['defaultLocation'] = user.get('defaultLocation')
|
|
|
|
# Get accessible locations
|
|
accessible_locations = []
|
|
location_settings = user.get('locationSettings', {})
|
|
if location_settings:
|
|
for loc_code, settings in location_settings.items():
|
|
if settings.get('accessible', False):
|
|
accessible_locations.append(loc_code)
|
|
|
|
session['accessibleLocations'] = accessible_locations
|
|
|
|
# Check if user needs to select a location
|
|
requiresLocationSelection = len(accessible_locations) > 1
|
|
|
|
# If only one location or no accessible locations, auto-select default
|
|
if not requiresLocationSelection:
|
|
session['currentLocation'] = user.get('defaultLocation')
|
|
|
|
return jsonify({
|
|
'status': 'success',
|
|
'message': 'Login successful',
|
|
'requiresLocationSelection': requiresLocationSelection
|
|
})
|
|
|
|
except Exception as e:
|
|
return jsonify({
|
|
'status': 'error',
|
|
'message': str(e)
|
|
}), 500
|
|
|
|
@auth_bp.route('/api/select-location', methods=['POST'])
|
|
def select_location():
|
|
"""Select a location for the current session"""
|
|
if 'username' not in session:
|
|
return jsonify({
|
|
'status': 'error',
|
|
'message': 'Not logged in'
|
|
}), 401
|
|
|
|
try:
|
|
data = request.json
|
|
location = data.get('location')
|
|
|
|
# Verify user has access to this location
|
|
accessible = session.get('accessibleLocations', [])
|
|
if location not in accessible:
|
|
return jsonify({
|
|
'status': 'error',
|
|
'message': 'You do not have access to this location'
|
|
}), 403
|
|
|
|
session['currentLocation'] = location
|
|
|
|
return jsonify({
|
|
'status': 'success',
|
|
'message': 'Location selected',
|
|
'currentLocation': location
|
|
})
|
|
|
|
except Exception as e:
|
|
return jsonify({
|
|
'status': 'error',
|
|
'message': str(e)
|
|
}), 500
|
|
|
|
@auth_bp.route('/logout')
|
|
def logout():
|
|
"""Log out user and clear session"""
|
|
session.clear()
|
|
return redirect(url_for('auth.login_page'))
|
|
|
|
@auth_bp.route('/api/session', methods=['GET'])
|
|
def get_session():
|
|
"""Get current session information"""
|
|
if 'username' not in session:
|
|
return jsonify({
|
|
'status': 'error',
|
|
'message': 'Not logged in'
|
|
}), 401
|
|
|
|
# Get user permissions
|
|
user = get_current_user()
|
|
permissions = {}
|
|
if user:
|
|
permissions = user.get('permissions', {})
|
|
|
|
return jsonify({
|
|
'status': 'success',
|
|
'username': session.get('username'),
|
|
'defaultLocation': session.get('defaultLocation'),
|
|
'currentLocation': session.get('currentLocation'),
|
|
'accessibleLocations': session.get('accessibleLocations', []),
|
|
'permissions': permissions
|
|
})
|