04/28 Fixed bugs

This commit is contained in:
2026-04-28 15:08:14 -04:00
parent 057b88edb7
commit 30933c39aa
4 changed files with 101 additions and 70 deletions
+45 -31
View File
@@ -35,25 +35,34 @@ def qr_statistics():
qr_code_filter = request.args.get('qr_code', '')
project_filter = request.args.get('project', '')
# Build date filter
date_filter = ""
# Build parameterized filter conditions (fixes SQL injection)
conditions = []
params = {}
if date_from:
date_filter += f" AND ad.check_in_date >= '{date_from}'"
conditions.append("ad.check_in_date >= :date_from")
params["date_from"] = date_from
if date_to:
date_filter += f" AND ad.check_in_date <= '{date_to}'"
# QR Code filter
qr_filter = ""
conditions.append("ad.check_in_date <= :date_to")
params["date_to"] = date_to
if qr_code_filter:
qr_filter = f" AND ad.qr_code_id = {qr_code_filter}"
# Project filter
project_filter_clause = ""
try:
params["qr_code_id"] = int(qr_code_filter)
conditions.append("ad.qr_code_id = :qr_code_id")
except (ValueError, TypeError):
logger_handler.logger.warning(f"Invalid qr_code filter value ignored: {qr_code_filter!r}")
if project_filter:
project_filter_clause = f" AND qc.project_id = {project_filter}"
try:
params["project_id"] = int(project_filter)
conditions.append("qc.project_id = :project_id")
except (ValueError, TypeError):
logger_handler.logger.warning(f"Invalid project filter value ignored: {project_filter!r}")
# Compose a reusable AND clause (empty string when no filters applied)
filter_clause = (" AND " + " AND ".join(conditions)) if conditions else ""
# 1. General Statistics
general_stats = db.session.execute(text(f"""
general_stats = db.session.execute(text("""
SELECT
COUNT(*) as total_scans,
COUNT(DISTINCT ad.employee_id) as unique_users,
@@ -64,11 +73,11 @@ def qr_statistics():
COUNT(CASE WHEN ad.latitude IS NOT NULL AND ad.longitude IS NOT NULL THEN 1 END) as gps_enabled_scans
FROM attendance_data ad
LEFT JOIN qr_codes qc ON ad.qr_code_id = qc.id
WHERE 1=1 {date_filter} {qr_filter} {project_filter_clause}
""")).fetchone()
WHERE 1=1
""" + filter_clause), params).fetchone()
# 2. Device Statistics
device_stats = db.session.execute(text(f"""
device_stats = db.session.execute(text("""
SELECT
CASE
WHEN device_info LIKE '%iPhone%' OR device_info LIKE '%iOS%' THEN 'iOS'
@@ -82,13 +91,14 @@ def qr_statistics():
COUNT(DISTINCT employee_id) as unique_users
FROM attendance_data ad
LEFT JOIN qr_codes qc ON ad.qr_code_id = qc.id
WHERE device_info IS NOT NULL {date_filter} {qr_filter} {project_filter_clause}
WHERE device_info IS NOT NULL
""" + filter_clause + """
GROUP BY device_type
ORDER BY scan_count DESC
""")).fetchall()
"""), params).fetchall()
# 3. Browser Statistics (from User Agent)
browser_stats = db.session.execute(text(f"""
browser_stats = db.session.execute(text("""
SELECT
CASE
WHEN user_agent LIKE '%Chrome%' AND user_agent NOT LIKE '%Edge%' THEN 'Chrome'
@@ -102,13 +112,14 @@ def qr_statistics():
COUNT(DISTINCT employee_id) as unique_users
FROM attendance_data ad
LEFT JOIN qr_codes qc ON ad.qr_code_id = qc.id
WHERE user_agent IS NOT NULL {date_filter} {qr_filter} {project_filter_clause}
WHERE user_agent IS NOT NULL
""" + filter_clause + """
GROUP BY browser_type
ORDER BY scan_count DESC
""")).fetchall()
"""), params).fetchall()
# 4. Location Statistics
location_stats = db.session.execute(text(f"""
# 4. Location Statistics
location_stats = db.session.execute(text("""
SELECT
qc.name as qr_name,
qc.location as qr_location,
@@ -120,13 +131,14 @@ def qr_statistics():
MAX(ad.check_in_date) as last_scan
FROM attendance_data ad
JOIN qr_codes qc ON ad.qr_code_id = qc.id
WHERE 1=1 {date_filter} {qr_filter} {project_filter_clause}
WHERE 1=1
""" + filter_clause + """
GROUP BY qc.id, qc.name, qc.location, qc.location_event
ORDER BY total_scans DESC
""")).fetchall()
"""), params).fetchall()
# 5. IP Address Analysis (Top 3 Most Active)
ip_stats = db.session.execute(text(f"""
ip_stats = db.session.execute(text("""
SELECT
ip_address,
COUNT(*) as scan_count,
@@ -136,14 +148,15 @@ def qr_statistics():
MAX(check_in_date) as last_scan
FROM attendance_data ad
LEFT JOIN qr_codes qc ON ad.qr_code_id = qc.id
WHERE ip_address IS NOT NULL {date_filter} {qr_filter} {project_filter_clause}
WHERE ip_address IS NOT NULL
""" + filter_clause + """
GROUP BY ip_address
ORDER BY scan_count DESC
LIMIT 3
""")).fetchall()
"""), params).fetchall()
# 6. Project Statistics (if projects exist)
project_stats = db.session.execute(text(f"""
project_stats = db.session.execute(text("""
SELECT
p.id,
p.name as project_name,
@@ -154,10 +167,11 @@ def qr_statistics():
FROM attendance_data ad
JOIN qr_codes qc ON ad.qr_code_id = qc.id
LEFT JOIN projects p ON qc.project_id = p.id
WHERE p.id IS NOT NULL {date_filter} {qr_filter} {project_filter_clause}
WHERE p.id IS NOT NULL
""" + filter_clause + """
GROUP BY p.id, p.name
ORDER BY total_scans DESC
""")).fetchall()
"""), params).fetchall()
# Get dropdown options for filters
qr_codes_list = db.session.execute(text("""