From 26b6fa3871c00ce6f8a805ed8deabaffb7954590 Mon Sep 17 00:00:00 2001 From: Nguyen Ngo Date: Mon, 11 Aug 2025 10:58:52 -0400 Subject: [PATCH] Updated activate/deactivate user function --- app.py | 129 ++++++++++++++- templates/users.html | 379 ++++++++++++++++++++++++++----------------- 2 files changed, 356 insertions(+), 152 deletions(-) diff --git a/app.py b/app.py index a8983aa..996bdb0 100644 --- a/app.py +++ b/app.py @@ -1506,18 +1506,141 @@ def edit_user(user_id): flash('Error updating user. Please try again.', 'error') return redirect(url_for('users')) +@app.route('/users//toggle_status', methods=['POST']) +@admin_required +def toggle_user_status(user_id): + """Toggle user active status (Admin only)""" + try: + user_to_toggle = User.query.get(user_id) + current_user = User.query.get(session['user_id']) + + if not user_to_toggle: + return jsonify({ + 'success': False, + 'message': 'User not found.' + }), 404 + + # Prevent self-deactivation + if user_to_toggle.id == current_user.id: + return jsonify({ + 'success': False, + 'message': 'You cannot deactivate yourself.' + }), 400 + + # Check if this is the last admin being deactivated + if (user_to_toggle.role == 'admin' and user_to_toggle.active_status == True): + active_admin_count = User.query.filter_by(role='admin', active_status=True).count() + if active_admin_count <= 1: + return jsonify({ + 'success': False, + 'message': 'Cannot deactivate the last admin user.' + }), 400 + + # Toggle the status + new_status = not user_to_toggle.active_status + user_to_toggle.active_status = new_status + db.session.commit() + + action = 'activated' if new_status else 'deactivated' + message = f'"{user_to_toggle.full_name}" has been {action} successfully.' + + print(f"Admin {current_user.username} {action} user {user_to_toggle.username}") + + return jsonify({ + 'success': True, + 'message': message, + 'new_status': new_status, + 'user_id': user_id + }) + + except Exception as e: + db.session.rollback() + print(f"Error toggling user status: {e}") + return jsonify({ + 'success': False, + 'message': 'Error updating user status. Please try again.' + }), 500 + +@app.route('/users//activate', methods=['GET', 'POST']) +@admin_required +def activate_user(user_id): + """Activate a user (Admin only) - Alternative route""" + try: + user_to_activate = User.query.get(user_id) + current_user = User.query.get(session['user_id']) + + if not user_to_activate: + flash('User not found.', 'error') + return redirect(url_for('users')) + + if user_to_activate.active_status: + flash('User is already active.', 'info') + else: + user_to_activate.active_status = True + db.session.commit() + flash(f'"{user_to_activate.full_name}" has been activated.', 'success') + print(f"Admin {current_user.username} activated user {user_to_activate.username}") + + return redirect(url_for('users')) + + except Exception as e: + db.session.rollback() + print(f"Error activating user: {e}") + flash('Error activating user. Please try again.', 'error') + return redirect(url_for('users')) + +@app.route('/users//deactivate', methods=['GET', 'POST']) +@admin_required +def deactivate_user(user_id): + """Deactivate a user (Admin only) - Alternative route""" + try: + user_to_deactivate = User.query.get(user_id) + current_user = User.query.get(session['user_id']) + + if not user_to_deactivate: + flash('User not found.', 'error') + return redirect(url_for('users')) + + # Prevent self-deactivation + if user_to_deactivate.id == current_user.id: + flash('You cannot deactivate yourself.', 'error') + return redirect(url_for('users')) + + # Check if this is the last admin + if user_to_deactivate.role == 'admin' and user_to_deactivate.active_status: + active_admin_count = User.query.filter_by(role='admin', active_status=True).count() + if active_admin_count <= 1: + flash('Cannot deactivate the last admin user.', 'error') + return redirect(url_for('users')) + + if not user_to_deactivate.active_status: + flash('User is already deactivated.', 'info') + else: + user_to_deactivate.active_status = False + db.session.commit() + flash(f'"{user_to_deactivate.full_name}" has been deactivated.', 'success') + print(f"Admin {current_user.username} deactivated user {user_to_deactivate.username}") + + return redirect(url_for('users')) + + except Exception as e: + db.session.rollback() + print(f"Error deactivating user: {e}") + flash('Error deactivating user. Please try again.', 'error') + return redirect(url_for('users')) + # ENHANCED USER STATISTICS API @app.route('/api/users/stats') @admin_required def user_stats_api(): - """API endpoint for user statistics""" - payroll_users = User.query.filter_by(role='payroll', active_status=True).count() - project_manager_users = User.query.filter_by(role='project_manager', active_status=True).count() + """UPDATED: API endpoint for user statistics - includes new roles""" try: total_users = User.query.count() active_users = User.query.filter_by(active_status=True).count() admin_users = User.query.filter_by(role='admin', active_status=True).count() staff_users = User.query.filter_by(role='staff', active_status=True).count() + payroll_users = User.query.filter_by(role='payroll', active_status=True).count() + project_manager_users = User.query.filter_by(role='project_manager', active_status=True).count() inactive_users = User.query.filter_by(active_status=False).count() # Recent registrations (last 30 days) diff --git a/templates/users.html b/templates/users.html index 0e68e14..cdcebd9 100644 --- a/templates/users.html +++ b/templates/users.html @@ -1,11 +1,12 @@ -{% extends "base_authenticated.html" %} {% block title %}User Management - QR -Code Management{% endblock %} {% block extra_head %} +{% extends "base_authenticated.html" %} +{% block title %}User Management - QR Code Management{% endblock %} + +{% block extra_head %} - -{% endblock %} {% block content %} + +{% endblock %} + +{% block content %}
@@ -31,10 +32,7 @@ Code Management{% endblock %} {% block extra_head %}
-

- {{ users|selectattr('role', 'equalto', - 'admin')|selectattr('active_status', 'equalto', True)|list|length }} -

+

{{ users|selectattr('role', 'equalto', 'admin')|selectattr('active_status', 'equalto', True)|list|length }}

Active Administrators

@@ -44,10 +42,7 @@ Code Management{% endblock %} {% block extra_head %}
-

- {{ users|selectattr('role', 'equalto', - 'staff')|selectattr('active_status', 'equalto', True)|list|length }} -

+

{{ users|selectattr('role', 'equalto', 'staff')|selectattr('active_status', 'equalto', True)|list|length }}

Active Staff Members

@@ -57,10 +52,7 @@ Code Management{% endblock %} {% block extra_head %}
-

- {{ users|selectattr('role', 'equalto', - 'payroll')|selectattr('active_status', 'equalto', True)|list|length }} -

+

{{ users|selectattr('role', 'equalto', 'payroll')|selectattr('active_status', 'equalto', True)|list|length }}

Payroll Specialists

@@ -70,11 +62,7 @@ Code Management{% endblock %} {% block extra_head %}
-

- {{ users|selectattr('role', 'equalto', - 'project_manager')|selectattr('active_status', 'equalto', - True)|list|length }} -

+

{{ users|selectattr('role', 'equalto', 'project_manager')|selectattr('active_status', 'equalto', True)|list|length }}

Project Managers

@@ -84,9 +72,7 @@ Code Management{% endblock %} {% block extra_head %}
-

- {{ users|selectattr('active_status', 'equalto', True)|list|length }} -

+

{{ users|selectattr('active_status', 'equalto', True)|list|length }}

Total Active Users

@@ -96,9 +82,7 @@ Code Management{% endblock %} {% block extra_head %}
-

- {{ users|selectattr('active_status', 'equalto', False)|list|length }} -

+

{{ users|selectattr('active_status', 'equalto', False)|list|length }}

Inactive Users

@@ -168,7 +152,7 @@ Code Management{% endblock %} {% block extra_head %} data-status="{{ 'active' if user.active_status else 'inactive' }}" > {{ loop.index }} - +