diff --git a/app.py b/app.py index 0c09244..aeaf9fc 100644 --- a/app.py +++ b/app.py @@ -70,6 +70,10 @@ class User(db.Model): def has_staff_permissions(self): """Check if user has staff-level permissions (includes new roles)""" return self.role in STAFF_LEVEL_ROLES + + def has_export_permissions(user_role): + """Check if user role has export permissions""" + return user_role in ['admin', 'payroll'] def get_role_display_name(self): """Get user-friendly role name""" @@ -3001,7 +3005,7 @@ def toggle_qr_status_api(qr_id): return redirect(url_for('dashboard')) @app.route('/attendance') -# @admin_required +@login_required def attendance_report(): """Safe attendance report with backward compatibility for location_accuracy and fixed datetime handling""" try: @@ -3009,6 +3013,7 @@ def attendance_report(): # Log attendance report access try: + user_role = session.get('role', 'unknown') logger_handler.logger.info(f"User {session.get('username', 'unknown')} accessed attendance report") except Exception as log_error: print(f"⚠️ Logging error (non-critical): {log_error}") @@ -3090,7 +3095,7 @@ def attendance_report(): conditions.append("ad.employee_id LIKE :employee") params['employee'] = f"%{employee_filter}%" - # FIXED: Apply project filter using SQL approach (not ORM) + # Apply project filter using SQL approach (not ORM) if project_filter: conditions.append("qc.project_id = :project_id") params['project_id'] = int(project_filter) @@ -3279,7 +3284,8 @@ def attendance_report(): project_filter=project_filter, today_date=today_date, current_date_formatted=current_date_formatted, - has_location_accuracy_feature=has_location_accuracy) + has_location_accuracy_feature=has_location_accuracy, + user_role=user_role) except Exception as e: print(f"❌ Error loading attendance report: {e}") @@ -3491,14 +3497,21 @@ def attendance_stats_api(): return jsonify({'error': 'Failed to fetch attendance statistics'}), 500 @app.route('/export-configuration') -@admin_required +@login_required def export_configuration(): """Route to display export configuration page""" try: print("📊 Export configuration route accessed") + # Check if user has export permissions + user_role = session.get('role') + if user_role not in ['admin', 'payroll']: + logger_handler.logger.warning(f"User {session.get('username', 'unknown')} (role: {user_role}) attempted to access export configuration without permissions") + flash('Access denied. Only administrators and payroll staff can access export configuration.', 'error') + return redirect(url_for('attendance_report')) # Log export configuration access using your existing logger try: + logger_handler.logger.info(f"User {session.get('username', 'unknown')} (role: {user_role}) accessed export configuration") logger_handler.logger.info(f"User {session.get('username', 'unknown')} accessed export configuration page") except Exception as log_error: print(f"⚠️ Logging error (non-critical): {log_error}") @@ -3573,10 +3586,16 @@ def export_configuration(): return redirect(url_for('attendance_report')) @app.route('/generate-excel-export', methods=['POST']) -@admin_required +@login_required def generate_excel_export(): """Generate and download Excel file with selected columns in specified order""" try: + user_role = session.get('role') + if user_role not in ['admin', 'payroll']: + logger_handler.logger.warning(f"User {session.get('username', 'unknown')} (role: {user_role}) attempted unauthorized Excel export") + flash('Access denied. Only administrators and payroll staff can export data.', 'error') + return redirect(url_for('attendance_report')) + print("📊 Excel export generation started") # Log export action using your existing logger diff --git a/static/js/attendance_report.js b/static/js/attendance_report.js index 2c93ba7..98cd4dc 100644 --- a/static/js/attendance_report.js +++ b/static/js/attendance_report.js @@ -1017,8 +1017,19 @@ function exportAttendanceWithAccuracy() { } function exportAttendance() { + // Check user role before proceeding + const userRole = window.userRole; // Read from global variable set in template + console.log("Template - session.role:", '{{ session.role }}'); + console.log("Template - window.userRole set to:", window.userRole); + + if (!['admin', 'payroll'].includes(userRole)) { + console.log("Export access denied - insufficient privileges"); + alert("Access denied. Only administrators and payroll staff can export data."); + return; + } + // Log export action - console.log("Export button clicked - redirecting to configuration page"); + console.log(`Export button clicked by ${userRole} - redirecting to configuration page`); // Get current filters const currentFilters = getCurrentFilters(); @@ -1053,6 +1064,15 @@ function getCurrentFilters() { // Add a quick CSV export function as backup (keep existing functionality) function exportAttendanceCSV() { + // Check user role before proceeding + const userRole = window.userRole; + + if (!['admin', 'payroll'].includes(userRole)) { + console.log("CSV export access denied - insufficient privileges"); + alert("Access denied. Only administrators and payroll staff can export data."); + return; + } + // Build export URL with current filters for CSV const params = new URLSearchParams(); const filters = getCurrentFilters(); diff --git a/templates/attendance_report.html b/templates/attendance_report.html index 0a5e668..53ebb4c 100644 --- a/templates/attendance_report.html +++ b/templates/attendance_report.html @@ -10,7 +10,7 @@ {% endblock %} {% block content %} -