minor changes

This commit is contained in:
Nguyen Ngo
2025-08-04 16:58:56 -04:00
parent 07fdb8af97
commit 87a3b846b1
+2 -316
View File
@@ -173,6 +173,7 @@ class AttendanceData(db.Model):
'location_source': self.location_source 'location_source': self.location_source
} }
# Utility functions
def get_coordinates_from_address(address): def get_coordinates_from_address(address):
""" """
Get latitude and longitude from address using geocoding service Get latitude and longitude from address using geocoding service
@@ -213,110 +214,6 @@ def get_coordinates_from_address(address):
print(f"❌ Error geocoding address '{address}': {e}") print(f"❌ Error geocoding address '{address}': {e}")
return None, None return None, None
'''
def get_coordinates_from_address(address):
"""
Enhanced geocoding function to get latitude and longitude from address
Returns (lat, lng, accuracy) tuple or (None, None, None) if failed
"""
if not address or address.strip() == '':
return None, None, None
try:
# Using Nominatim (OpenStreetMap) geocoding service
url = "https://nominatim.openstreetmap.org/search"
params = {
'q': address,
'format': 'json',
'limit': 1,
'addressdetails': 1
}
headers = {
'User-Agent': 'QR-Attendance-System/1.0'
}
response = requests.get(url, params=params, headers=headers, timeout=10)
if response.status_code == 200:
data = response.json()
if data and len(data) > 0:
result = data[0]
lat = float(result['lat'])
lng = float(result['lon'])
# Determine accuracy based on result type
place_type = result.get('type', 'unknown')
osm_type = result.get('osm_type', 'unknown')
if place_type in ['house', 'building'] or osm_type == 'way':
accuracy = 'high'
elif place_type in ['neighbourhood', 'suburb', 'quarter']:
accuracy = 'medium'
else:
accuracy = 'low'
print(f"✅ Geocoded address: {address}")
print(f" Coordinates: {lat:.6f}, {lng:.6f}")
print(f" Accuracy: {accuracy} ({place_type})")
return lat, lng, accuracy
print(f"⚠️ No geocoding results for address: {address}")
return None, None, None
except requests.RequestException as e:
print(f"❌ Geocoding request error: {e}")
return None, None, None
except (ValueError, KeyError) as e:
print(f"❌ Geocoding parsing error: {e}")
return None, None, None
except Exception as e:
print(f"❌ Unexpected geocoding error: {e}")
return None, None, None
'''
'''
def get_coordinates_from_address(address):
"""
Get latitude and longitude from address using geocoding service
Returns (lat, lng) tuple or (None, None) if failed
"""
if not address or address.strip() == '':
return None, None
try:
# Using Nominatim/OpenStreetMap for free geocoding
url = "https://nominatim.openstreetmap.org/search"
params = {
'q': address,
'format': 'json',
'limit': 1,
'addressdetails': 1
}
headers = {
'User-Agent': 'QR-Attendance-System/1.0'
}
response = requests.get(url, params=params, headers=headers, timeout=10)
if response.status_code == 200:
data = response.json()
if data and len(data) > 0:
lat = float(data[0]['lat'])
lng = float(data[0]['lon'])
print(f"✅ Geocoded address '{address[:50]}...' to coordinates: {lat}, {lng}")
return lat, lng
print(f"⚠️ Could not geocode address: {address}")
return None, None
except Exception as e:
print(f"❌ Error geocoding address '{address}': {e}")
return None, None
'''
def get_coordinates_from_address_enhanced(address): def get_coordinates_from_address_enhanced(address):
""" """
Enhanced geocoding function with better error handling Enhanced geocoding function with better error handling
@@ -681,42 +578,6 @@ def calculate_distance_miles(lat1, lng1, lat2, lng2):
print(f"❌ Error calculating distance: {e}") print(f"❌ Error calculating distance: {e}")
return None return None
def calculate_location_accuracy(qr_address, checkin_address, checkin_lat=None, checkin_lng=None):
"""
Calculate location accuracy by comparing QR code address with check-in location
Returns distance in miles between the two locations
"""
print(f"\n📍 CALCULATING LOCATION ACCURACY:")
print(f" QR Address: {qr_address}")
print(f" Check-in Address: {checkin_address}")
print(f" Check-in Coordinates: {checkin_lat}, {checkin_lng}")
# Get QR code coordinates from address
qr_lat, qr_lng = get_coordinates_from_address(qr_address)
if qr_lat is None or qr_lng is None:
print(f"⚠️ Could not geocode QR address, cannot calculate accuracy")
return None
# Use check-in coordinates if available, otherwise geocode check-in address
if checkin_lat is not None and checkin_lng is not None:
checkin_coords_lat, checkin_coords_lng = checkin_lat, checkin_lng
print(f"✅ Using GPS coordinates for check-in location")
else:
checkin_coords_lat, checkin_coords_lng = get_coordinates_from_address(checkin_address)
if checkin_coords_lat is None or checkin_coords_lng is None:
print(f"⚠️ Could not geocode check-in address, cannot calculate accuracy")
return None
print(f"✅ Using geocoded coordinates for check-in address")
# Calculate distance
distance = calculate_distance_miles(qr_lat, qr_lng, checkin_coords_lat, checkin_coords_lng)
if distance is not None:
print(f"✅ Location accuracy calculated: {distance} miles")
return distance
def get_location_accuracy_level(location_accuracy): def get_location_accuracy_level(location_accuracy):
"""Get human-readable location accuracy level based on distance""" """Get human-readable location accuracy level based on distance"""
if not location_accuracy: if not location_accuracy:
@@ -750,7 +611,7 @@ def get_location_accuracy_level_enhanced(location_accuracy):
return 'poor' return 'poor'
else: # Greater than 1 mile else: # Greater than 1 mile
return 'very_poor' return 'very_poor'
'''
def process_location_data(location_data): def process_location_data(location_data):
""" """
Process and validate location data from form Process and validate location data from form
@@ -800,57 +661,7 @@ def process_location_data(location_data):
print(f"⚠️ Error processing location data: {e}") print(f"⚠️ Error processing location data: {e}")
return processed return processed
'''
def process_location_data(location_data):
"""
Process and validate location data from form
Returns clean location data or None values for invalid data
"""
processed = {
'latitude': None,
'longitude': None,
'accuracy': None,
'altitude': None,
'source': location_data.get('location_source', 'manual'),
'address': location_data.get('address', '')[:500] if location_data.get('address') else None
}
try:
# Process latitude
if location_data.get('latitude') and location_data['latitude'] not in ['null', '']:
lat = float(location_data['latitude'])
if -90 <= lat <= 90: # Valid latitude range
processed['latitude'] = lat
else:
print(f"⚠️ Invalid latitude: {lat}")
# Process longitude
if location_data.get('longitude') and location_data['longitude'] not in ['null', '']:
lng = float(location_data['longitude'])
if -180 <= lng <= 180: # Valid longitude range
processed['longitude'] = lng
else:
print(f"⚠️ Invalid longitude: {lng}")
# Process accuracy
if location_data.get('accuracy') and location_data['accuracy'] not in ['null', '']:
acc = float(location_data['accuracy'])
if acc >= 0: # Accuracy should be positive
processed['accuracy'] = acc
else:
print(f"⚠️ Invalid accuracy: {acc}")
# Process altitude
if location_data.get('altitude') and location_data['altitude'] not in ['null', '']:
alt = float(location_data['altitude'])
# Altitude can be negative (below sea level)
processed['altitude'] = alt
except (ValueError, TypeError) as e:
print(f"⚠️ Error processing location data: {e}")
return processed
'''
def process_location_data_enhanced(form_data): def process_location_data_enhanced(form_data):
""" """
Enhanced location data processing with better validation and error handling Enhanced location data processing with better validation and error handling
@@ -909,132 +720,7 @@ def process_location_data_enhanced(form_data):
print(f"⚠️ Error in enhanced location data processing: {e}") print(f"⚠️ Error in enhanced location data processing: {e}")
return processed return processed
'''
def process_location_data_enhanced(form_data):
"""
Enhanced location data processing with better validation and error handling
"""
processed = {
'latitude': None,
'longitude': None,
'accuracy': None,
'altitude': None,
'source': form_data.get('location_source', 'manual'),
'address': None
}
try:
# Enhanced latitude validation
if form_data.get('latitude') and form_data['latitude'] not in ['null', '', 'undefined']:
lat = float(form_data['latitude'])
if -90 <= lat <= 90:
processed['latitude'] = round(lat, 6) # 6 decimal precision
else:
print(f"⚠️ Invalid latitude range: {lat}")
# Enhanced longitude validation
if form_data.get('longitude') and form_data['longitude'] not in ['null', '', 'undefined']:
lng = float(form_data['longitude'])
if -180 <= lng <= 180:
processed['longitude'] = round(lng, 6) # 6 decimal precision
else:
print(f"⚠️ Invalid longitude range: {lng}")
# Enhanced accuracy validation
if form_data.get('accuracy') and form_data['accuracy'] not in ['null', '', 'undefined']:
acc = float(form_data['accuracy'])
if 0 <= acc <= 50000: # Reasonable accuracy range in meters
processed['accuracy'] = round(acc, 1)
else:
print(f"⚠️ Invalid accuracy value: {acc}")
# Enhanced altitude validation
if form_data.get('altitude') and form_data['altitude'] not in ['null', '', 'undefined']:
alt = float(form_data['altitude'])
if -1000 <= alt <= 10000: # Reasonable altitude range in meters
processed['altitude'] = round(alt, 1)
else:
print(f"⚠️ Invalid altitude value: {alt}")
# Enhanced address processing
if form_data.get('address'):
address = form_data['address'].strip()
if len(address) > 0:
processed['address'] = address[:500] # Limit to 500 characters
print(f"✅ Enhanced location data processed: {processed}")
except (ValueError, TypeError) as e:
print(f"⚠️ Error in enhanced location data processing: {e}")
return processed
'''
def migrate_to_enhanced_location_accuracy():
"""
Migration function to recalculate all existing records with enhanced accuracy
"""
try:
print("🔄 Starting enhanced location accuracy migration...")
# Get all records that need recalculation
records = db.session.execute(text("""
SELECT ad.id, qc.location_address, ad.address, ad.latitude, ad.longitude, ad.location_accuracy
FROM attendance_data ad
LEFT JOIN qr_codes qc ON ad.qr_code_id = qc.id
WHERE qc.location_address IS NOT NULL
""")).fetchall()
print(f"📊 Found {len(records)} records to process")
updated_count = 0
improved_count = 0
for record in records:
try:
# Calculate enhanced location accuracy
new_accuracy = calculate_location_accuracy_enhanced(
qr_address=record.location_address,
checkin_address=record.address,
checkin_lat=record.latitude,
checkin_lng=record.longitude
)
if new_accuracy is not None:
# Update the record
db.session.execute(text("""
UPDATE attendance_data
SET location_accuracy = :accuracy
WHERE id = :record_id
"""), {
'accuracy': new_accuracy,
'record_id': record.id
})
updated_count += 1
# Check if this is an improvement
if record.location_accuracy is None or abs(new_accuracy - (record.location_accuracy or 0)) > 0.001:
improved_count += 1
print(f" ✅ Updated record {record.id}: {record.location_accuracy}{new_accuracy:.4f} miles")
except Exception as e:
print(f" ⚠️ Error processing record {record.id}: {e}")
# Commit all changes
db.session.commit()
print(f"✅ Enhanced migration completed!")
print(f" 📊 Records processed: {len(records)}")
print(f" ✅ Records updated: {updated_count}")
print(f" 📈 Records improved: {improved_count}")
return True
except Exception as e:
print(f"❌ Enhanced migration failed: {e}")
db.session.rollback()
return False
'''
def migrate_to_enhanced_location_accuracy(): def migrate_to_enhanced_location_accuracy():
""" """
Migration function to recalculate all existing records with enhanced accuracy Migration function to recalculate all existing records with enhanced accuracy