User management and module improvements
- Added daily_mirror module to permissions system - Fixed user module management - updates now work correctly - Implemented dashboard module filtering based on user permissions - Fixed warehouse create_locations page (config parser and delete) - Implemented POST-Redirect-GET pattern to prevent duplicate entries - Added application license system with validation middleware - Cleaned up debug logging code - Improved user module selection with fetch API instead of form submit
This commit is contained in:
@@ -29,6 +29,28 @@ from .access_control import (
|
||||
bp = Blueprint('main', __name__)
|
||||
warehouse_bp = Blueprint('warehouse', __name__)
|
||||
|
||||
def check_app_license():
|
||||
"""Check if the application license is valid."""
|
||||
license_path = os.path.join(current_app.instance_path, 'app_license.json')
|
||||
|
||||
# If no license file exists, return invalid
|
||||
if not os.path.exists(license_path):
|
||||
return False, '⚠️ Application License Expired\n\nThis application requires a valid license to operate.\nPlease contact your superadmin to renew the license.'
|
||||
|
||||
try:
|
||||
with open(license_path, 'r') as f:
|
||||
license_data = json.load(f)
|
||||
|
||||
valid_until = datetime.strptime(license_data['valid_until'], '%Y-%m-%d')
|
||||
|
||||
# Check if license is still valid
|
||||
if datetime.utcnow().date() > valid_until.date():
|
||||
return False, f'⚠️ Application License Expired\n\nThe license expired on {license_data["valid_until"]}.\nPlease contact your superadmin to renew the license.'
|
||||
|
||||
return True, 'License valid'
|
||||
except Exception as e:
|
||||
return False, f'⚠️ License Validation Error\n\nCould not validate application license.\nPlease contact your superadmin.'
|
||||
|
||||
@bp.route('/main_scan')
|
||||
@requires_quality_module
|
||||
def main_scan():
|
||||
@@ -97,6 +119,15 @@ def login():
|
||||
user_modules = ['quality', 'warehouse', 'labels', 'daily_mirror']
|
||||
|
||||
session['modules'] = user_modules
|
||||
|
||||
# Check app license for non-superadmin users
|
||||
if user['role'] != 'superadmin':
|
||||
license_valid, license_message = check_app_license()
|
||||
if not license_valid:
|
||||
session.clear()
|
||||
flash(license_message, 'danger')
|
||||
return render_template('login.html')
|
||||
|
||||
print("Logged in as:", session.get('user'), session.get('role'), "modules:", user_modules)
|
||||
return redirect(url_for('main.dashboard'))
|
||||
else:
|
||||
@@ -191,7 +222,16 @@ def dashboard():
|
||||
print("Session user:", session.get('user'), session.get('role'))
|
||||
if 'user' not in session:
|
||||
return redirect(url_for('main.login'))
|
||||
return render_template('dashboard.html')
|
||||
|
||||
# Get user's modules and role
|
||||
user_role = session.get('role')
|
||||
user_modules = session.get('modules', [])
|
||||
|
||||
# Superadmin and admin see all modules
|
||||
if user_role in ['superadmin', 'admin']:
|
||||
user_modules = ['quality', 'warehouse', 'labels', 'daily_mirror']
|
||||
|
||||
return render_template('dashboard.html', user_modules=user_modules, user_role=user_role)
|
||||
|
||||
@bp.route('/settings')
|
||||
@admin_plus
|
||||
@@ -402,7 +442,7 @@ def quick_update_modules():
|
||||
# Get current user to validate role
|
||||
conn = get_db_connection()
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT username, role FROM users WHERE id=%s", (user_id,))
|
||||
cursor.execute("SELECT username, role, modules FROM users WHERE id=%s", (user_id,))
|
||||
user_row = cursor.fetchone()
|
||||
|
||||
if not user_row:
|
||||
@@ -410,11 +450,12 @@ def quick_update_modules():
|
||||
conn.close()
|
||||
return redirect(url_for('main.user_management_simple'))
|
||||
|
||||
username, role = user_row
|
||||
username, role, current_modules = user_row
|
||||
|
||||
# Validate modules for the role
|
||||
from app.permissions_simple import validate_user_modules
|
||||
is_valid, error_msg = validate_user_modules(role, modules)
|
||||
|
||||
if not is_valid:
|
||||
flash(f'Invalid module assignment: {error_msg}')
|
||||
conn.close()
|
||||
@@ -425,18 +466,25 @@ def quick_update_modules():
|
||||
if modules and role in ['manager', 'worker']:
|
||||
import json
|
||||
modules_json = json.dumps(modules)
|
||||
elif not modules and role in ['manager', 'worker']:
|
||||
# Empty modules list for manager/worker
|
||||
import json
|
||||
modules_json = json.dumps([])
|
||||
|
||||
# Update modules only
|
||||
cursor.execute("UPDATE users SET modules=%s WHERE id=%s", (modules_json, user_id))
|
||||
conn.commit()
|
||||
|
||||
conn.close()
|
||||
|
||||
flash(f'Modules updated successfully for user "{username}".')
|
||||
flash(f'Modules updated successfully for user "{username}". New modules: {", ".join(modules) if modules else "None"}', 'success')
|
||||
return redirect(url_for('main.user_management_simple'))
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error updating modules: {e}")
|
||||
flash('Error updating modules.')
|
||||
print(f"ERROR updating modules: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
flash(f'Error updating modules: {str(e)}', 'danger')
|
||||
return redirect(url_for('main.user_management_simple'))
|
||||
|
||||
@bp.route('/reports')
|
||||
@@ -2398,7 +2446,64 @@ def download_extension():
|
||||
keys = []
|
||||
except Exception as e:
|
||||
keys = []
|
||||
return render_template('download_extension.html', pairing_keys=keys)
|
||||
|
||||
# Load app license key
|
||||
license_path = os.path.join(current_app.instance_path, 'app_license.json')
|
||||
license_data = None
|
||||
try:
|
||||
if os.path.exists(license_path):
|
||||
with open(license_path, 'r') as f:
|
||||
license_data = json.load(f)
|
||||
|
||||
# Calculate days remaining
|
||||
valid_until = datetime.strptime(license_data['valid_until'], '%Y-%m-%d')
|
||||
days_remaining = (valid_until.date() - datetime.utcnow().date()).days
|
||||
license_data['days_remaining'] = days_remaining
|
||||
except Exception as e:
|
||||
license_data = None
|
||||
|
||||
return render_template('download_extension.html', pairing_keys=keys, license_data=license_data)
|
||||
|
||||
@bp.route('/generate_app_license', methods=['POST'])
|
||||
@superadmin_only
|
||||
def generate_app_license():
|
||||
"""Generate a license key for the application."""
|
||||
validity_days = int(request.form.get('validity_days', 365)) # Default to 365 days
|
||||
|
||||
# Generate a secure license key
|
||||
license_key = secrets.token_urlsafe(48)
|
||||
valid_until = (datetime.utcnow() + timedelta(days=validity_days)).strftime('%Y-%m-%d')
|
||||
created_at = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
|
||||
|
||||
# Create license data
|
||||
license_data = {
|
||||
'license_key': license_key,
|
||||
'valid_until': valid_until,
|
||||
'created_at': created_at,
|
||||
'validity_days': validity_days
|
||||
}
|
||||
|
||||
# Save license key
|
||||
license_path = os.path.join(current_app.instance_path, 'app_license.json')
|
||||
with open(license_path, 'w') as f:
|
||||
json.dump(license_data, f, indent=2)
|
||||
|
||||
flash(f'App license generated successfully (valid for {validity_days} days until {valid_until}).', 'success')
|
||||
return redirect(url_for('main.download_extension'))
|
||||
|
||||
@bp.route('/revoke_app_license', methods=['POST'])
|
||||
@superadmin_only
|
||||
def revoke_app_license():
|
||||
"""Revoke the application license."""
|
||||
license_path = os.path.join(current_app.instance_path, 'app_license.json')
|
||||
|
||||
if os.path.exists(license_path):
|
||||
os.remove(license_path)
|
||||
flash('App license revoked successfully.', 'success')
|
||||
else:
|
||||
flash('No license key found to revoke.', 'warning')
|
||||
|
||||
return redirect(url_for('main.download_extension'))
|
||||
|
||||
@bp.route('/extension_files/<path:filename>')
|
||||
def extension_files(filename):
|
||||
|
||||
Reference in New Issue
Block a user