diff --git a/app.py b/app.py
index d79105a..e8b84df 100644
--- a/app.py
+++ b/app.py
@@ -2422,7 +2422,7 @@ def create_qr_code():
@login_required
@log_database_operations('qr_code_edit')
def edit_qr_code(qr_id):
- """Enhanced edit QR code with project association and URL regeneration"""
+ """Enhanced edit QR code with project association and URL regeneration - COORDINATE FIX"""
try:
qr_code = QRCode.query.get_or_404(qr_id)
@@ -2434,7 +2434,10 @@ def edit_qr_code(qr_id):
'location_address': qr_code.location_address,
'location_event': qr_code.location_event,
'project_id': qr_code.project_id,
- 'qr_url': qr_code.qr_url
+ 'qr_url': qr_code.qr_url,
+ 'address_latitude': qr_code.address_latitude,
+ 'address_longitude': qr_code.address_longitude,
+ 'coordinate_accuracy': qr_code.coordinate_accuracy
}
# Update QR code fields
@@ -2444,11 +2447,12 @@ def edit_qr_code(qr_id):
qr_code.location_address = request.form['location_address']
qr_code.location_event = request.form.get('location_event', '')
- # Handle coordinates update
- latitude = request.form.get('latitude')
- longitude = request.form.get('longitude')
+ # SIMPLIFIED COORDINATE HANDLING - Remove validation requirement
+ latitude = request.form.get('address_latitude') # Changed from 'latitude' to match form
+ longitude = request.form.get('address_longitude') # Changed from 'longitude' to match form
coordinate_accuracy = request.form.get('coordinate_accuracy', 'geocoded')
+ # Update coordinates if provided, or keep existing ones
if latitude and longitude:
try:
qr_code.address_latitude = float(latitude)
@@ -2456,19 +2460,33 @@ def edit_qr_code(qr_id):
qr_code.coordinate_accuracy = coordinate_accuracy
qr_code.coordinates_updated_date = datetime.utcnow()
except (ValueError, TypeError):
- pass # Keep existing coordinates if invalid
+ # If invalid coordinates, keep existing ones
+ pass
+ elif latitude == '' and longitude == '':
+ # Explicitly clear coordinates if empty strings are sent
+ qr_code.address_latitude = None
+ qr_code.address_longitude = None
+ qr_code.coordinate_accuracy = None
+ qr_code.coordinates_updated_date = None
+ # If no coordinate data is provided, keep existing coordinates unchanged
- # Handle project association
+ # Handle project association - FIXED LOGIC
new_project_id = request.form.get('project_id')
- if new_project_id:
- new_project_id = int(new_project_id)
- project = Project.query.get(new_project_id)
- if project and project.active_status:
- qr_code.project_id = new_project_id
- else:
- flash('Selected project is not valid or inactive.', 'error')
+ if new_project_id and new_project_id.strip(): # Check for non-empty string
+ try:
+ new_project_id = int(new_project_id)
+ project = Project.query.get(new_project_id)
+ if project and project.active_status:
+ qr_code.project_id = new_project_id
+ else:
+ flash('Selected project is not valid or inactive.', 'error')
+ return render_template('edit_qr_code.html', qr_code=qr_code, projects=Project.query.filter_by(active_status=True).all())
+ except (ValueError, TypeError):
+ # Invalid project_id format
+ flash('Invalid project selection.', 'error')
return render_template('edit_qr_code.html', qr_code=qr_code, projects=Project.query.filter_by(active_status=True).all())
else:
+ # Empty or None project_id means unassign from project
qr_code.project_id = None
# Regenerate URL if name changed
@@ -2483,16 +2501,24 @@ def edit_qr_code(qr_id):
qr_code.qr_url = new_qr_url
qr_code.qr_code_image = new_qr_image
+ # ENHANCED CHANGE DETECTION
+ project_changed = old_data['project_id'] != qr_code.project_id
+ coordinates_changed = (old_data['address_latitude'] != qr_code.address_latitude or
+ old_data['address_longitude'] != qr_code.address_longitude)
+
db.session.commit()
- # Log changes
+ # Log changes with improved tracking
new_data = {
'name': qr_code.name,
'location': qr_code.location,
'location_address': qr_code.location_address,
'location_event': qr_code.location_event,
'project_id': qr_code.project_id,
- 'qr_url': qr_code.qr_url
+ 'qr_url': qr_code.qr_url,
+ 'address_latitude': qr_code.address_latitude,
+ 'address_longitude': qr_code.address_longitude,
+ 'coordinate_accuracy': qr_code.coordinate_accuracy
}
changes = {}
@@ -2500,11 +2526,53 @@ def edit_qr_code(qr_id):
if old_data[key] != new_data[key]:
changes[key] = {'old': old_data[key], 'new': new_data[key]}
+ # Enhanced logging for all changes
if changes:
logger_handler.logger.info(f"User {session['username']} updated QR code {qr_id}: {json.dumps(changes)}")
+
+ # Log specific change actions
+ if project_changed:
+ old_project_name = None
+ new_project_name = None
+
+ if old_data['project_id']:
+ old_project = Project.query.get(old_data['project_id'])
+ old_project_name = old_project.name if old_project else f"Project ID {old_data['project_id']}"
+
+ if qr_code.project_id:
+ new_project = Project.query.get(qr_code.project_id)
+ new_project_name = new_project.name if new_project else f"Project ID {qr_code.project_id}"
+
+ project_change_msg = f"QR code '{qr_code.name}' project changed from '{old_project_name or 'No Project'}' to '{new_project_name or 'No Project'}'"
+ logger_handler.logger.info(f"User {session['username']} - {project_change_msg}")
+
+ if coordinates_changed:
+ coord_change_msg = f"QR code '{qr_code.name}' coordinates updated"
+ if qr_code.has_coordinates:
+ coord_change_msg += f" to {qr_code.coordinates_display}"
+ else:
+ coord_change_msg += " (coordinates cleared)"
+ logger_handler.logger.info(f"User {session['username']} - {coord_change_msg}")
+ # Success message with detailed information
url_message = f" URL updated to: {qr_code.qr_url}" if name_changed else ""
- flash(f'QR Code "{qr_code.name}" updated successfully!{url_message}', 'success')
+ project_message = ""
+ coord_message = ""
+
+ if project_changed:
+ if qr_code.project_id:
+ current_project = Project.query.get(qr_code.project_id)
+ project_message = f" Project updated to: {current_project.name if current_project else 'Unknown'}"
+ else:
+ project_message = " Removed from project"
+
+ if coordinates_changed:
+ if qr_code.has_coordinates:
+ coord_message = f" Coordinates updated: {qr_code.coordinates_display}"
+ else:
+ coord_message = " Coordinates cleared"
+
+ flash(f'QR Code "{qr_code.name}" updated successfully!{url_message}{project_message}{coord_message}', 'success')
return redirect(url_for('dashboard'))
# Get active projects for dropdown
diff --git a/templates/edit_qr_code.html b/templates/edit_qr_code.html
index 5d64530..9bed09b 100644
--- a/templates/edit_qr_code.html
+++ b/templates/edit_qr_code.html
@@ -777,6 +777,7 @@
};
let originalData = {};
+ let originalProjectId = {% if qr_code.project_id %}{{ qr_code.project_id }}{% else %}null{% endif %};
// Initialize the form when page loads
document.addEventListener('DOMContentLoaded', function() {
@@ -797,25 +798,15 @@
}
function initializeForm() {
- // Form validation on submit
+ // Form validation on submit - REMOVED COORDINATE UPDATE REQUIREMENT
document.getElementById('editQRForm').addEventListener('submit', function(e) {
if (!validateForm()) {
e.preventDefault();
return false;
}
- // Check if changes were made
- if (!hasChanges()) {
- e.preventDefault();
- showStatus('warning', 'No changes detected. Please modify the information to update the QR code.');
- return false;
- }
-
- // Confirm changes before submission
- if (!confirmSaveChanges()) {
- e.preventDefault();
- return false;
- }
+ // REMOVED: Check if changes were made - Allow form submission regardless of changes
+ // This enables updates even when only project changes or coordinate updates occur
// Show loading state
const submitBtn = document.getElementById('submitBtn');
@@ -851,87 +842,56 @@
});
}
- function initializeCoordinatesFeature() {
- const geocodeBtn = document.getElementById('geocodeBtn');
- const clearBtn = document.getElementById('clearCoordinatesBtn');
-
- // Geocode button click
- geocodeBtn.addEventListener('click', function() {
- const address = document.getElementById('location_address').value.trim();
- if (address.length > 10) {
- geocodeAddress(address);
- } else {
- showStatus('error', 'Please enter a complete address first');
- }
- });
-
- // Clear coordinates button
- clearBtn.addEventListener('click', clearCoordinates);
- }
-
- function initializeChangeTracking() {
- const inputs = document.querySelectorAll('#name, #location, #location_address, #location_event');
-
- inputs.forEach(input => {
- input.addEventListener('input', updateCurrentInfo);
- });
- }
-
- function updateCurrentInfo() {
- document.getElementById('currentName').textContent = document.getElementById('name').value || '-';
- document.getElementById('currentLocation').textContent = document.getElementById('location').value || '-';
- document.getElementById('currentEvent').textContent = document.getElementById('location_event').value || '-';
- document.getElementById('currentAddress').textContent = document.getElementById('location_address').value || '-';
- }
-
- async function geocodeAddress(address) {
+ function geocodeAddress(address) {
const geocodeBtn = document.getElementById('geocodeBtn');
const statusDiv = document.getElementById('coordinateStatus');
// Show loading state
- geocodeBtn.innerHTML = ' Getting coordinates...';
+ geocodeBtn.innerHTML = ' Getting Coordinates...';
geocodeBtn.disabled = true;
- try {
- const response = await fetch('/api/geocode', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({ address: address })
+ showStatus('info', 'Getting coordinates from address...');
+
+ const geocodeUrl = `https://api.opencagedata.com/geocode/v1/json?q=${encodeURIComponent(address)}&key=b0e9dd83c98e4cfebc6a9ef1d83f5a6e&limit=1&countrycode=my&language=en`;
+
+ fetch(geocodeUrl)
+ .then(response => response.json())
+ .then(data => {
+ console.log('Geocoding response:', data);
+
+ if (data.results && data.results.length > 0) {
+ const result = data.results[0];
+ const lat = result.geometry.lat;
+ const lng = result.geometry.lng;
+ const confidence = result.confidence || 0;
+
+ // Update coordinates data
+ coordinatesData = {
+ latitude: lat,
+ longitude: lng,
+ accuracy: confidence >= 8 ? 'high' : confidence >= 5 ? 'medium' : 'low'
+ };
+
+ updateCoordinatesDisplay();
+ updateHiddenFields();
+
+ const confidenceText = confidence >= 8 ? 'high' : confidence >= 5 ? 'medium' : 'low';
+ showStatus('success', `Coordinates updated successfully! Accuracy: ${confidenceText}`);
+
+ console.log('✓ Coordinates updated:', coordinatesData);
+ } else {
+ showStatus('error', 'Could not find coordinates for this address. Please check the address and try again.');
+ }
+ })
+ .catch(error => {
+ console.error('Geocoding error:', error);
+ showStatus('error', 'Failed to get coordinates. Please try again.');
+ })
+ .finally(() => {
+ // Reset button state
+ geocodeBtn.innerHTML = ' Update Coordinates';
+ geocodeBtn.disabled = false;
});
-
- const result = await response.json();
-
- if (result.success) {
- // Update coordinates
- coordinatesData = {
- latitude: result.data.latitude,
- longitude: result.data.longitude,
- accuracy: result.data.accuracy
- };
-
- // Update display
- updateCoordinatesDisplay();
-
- // Update hidden form fields
- updateHiddenFields();
-
- // Show success message
- showStatus('success', result.message);
-
- } else {
- showStatus('error', result.message);
- }
-
- } catch (error) {
- console.error('Geocoding error:', error);
- showStatus('error', 'Network error occurred. Please try again.');
- }
-
- // Reset button state
- geocodeBtn.innerHTML = ' Update Coordinates';
- geocodeBtn.disabled = false;
}
function updateCoordinatesDisplay() {
@@ -972,6 +932,7 @@
showStatus('warning', 'Coordinates cleared. Click "Update QR Code" to save changes.');
}
+ // ENHANCED hasChanges function - Now includes project changes and allows coordinate-only updates
function hasChanges() {
const currentData = {
name: document.getElementById('name').value.trim(),
@@ -980,30 +941,35 @@
location_event: document.getElementById('location_event').value.trim()
};
- return Object.keys(originalData).some(key => {
+ // Check basic field changes
+ const fieldChanges = Object.keys(originalData).some(key => {
return currentData[key] !== originalData[key];
});
+
+ // Check project changes
+ const currentProjectId = document.getElementById('project_id').value;
+ const projectIdValue = currentProjectId ? parseInt(currentProjectId) : null;
+ const projectChanged = originalProjectId !== projectIdValue;
+
+ console.log('Change detection:', {
+ fieldChanges,
+ projectChanged,
+ originalProjectId,
+ currentProjectId: projectIdValue
+ });
+
+ return fieldChanges || projectChanged;
}
- function confirmSaveChanges() {
- const changeCount = Object.keys(originalData).filter(key => {
- const currentValue = document.getElementById(key).value.trim();
- return currentValue !== originalData[key];
- }).length;
-
- return confirm(
- `You have made ${changeCount} change${changeCount !== 1 ? 's' : ''} to this QR code.\n\n` +
- 'Saving will update the QR code with the new information.\n\n' +
- 'Are you sure you want to continue?'
- );
- }
+ // REMOVED: confirmSaveChanges function - No longer needed since we're allowing all updates
function showStatus(type, message) {
const statusDiv = document.getElementById('coordinateStatus');
const iconMap = {
'success': 'fas fa-check-circle',
'error': 'fas fa-exclamation-circle',
- 'warning': 'fas fa-exclamation-triangle'
+ 'warning': 'fas fa-exclamation-triangle',
+ 'info': 'fas fa-info-circle'
};
statusDiv.innerHTML = `
@@ -1080,6 +1046,39 @@
errorElement.remove();
}
}
+
+ function initializeCoordinatesFeature() {
+ const geocodeBtn = document.getElementById('geocodeBtn');
+ const clearBtn = document.getElementById('clearCoordinatesBtn');
+
+ // Geocode button click
+ geocodeBtn.addEventListener('click', function() {
+ const address = document.getElementById('location_address').value.trim();
+ if (address.length > 10) {
+ geocodeAddress(address);
+ } else {
+ showStatus('error', 'Please enter a complete address first');
+ }
+ });
+
+ // Clear coordinates button
+ clearBtn.addEventListener('click', clearCoordinates);
+ }
+
+ function initializeChangeTracking() {
+ const inputs = document.querySelectorAll('#name, #location, #location_address, #location_event');
+
+ inputs.forEach(input => {
+ input.addEventListener('input', updateCurrentInfo);
+ });
+ }
+
+ function updateCurrentInfo() {
+ document.getElementById('currentName').textContent = document.getElementById('name').value || '-';
+ document.getElementById('currentLocation').textContent = document.getElementById('location').value || '-';
+ document.getElementById('currentEvent').textContent = document.getElementById('location_event').value || '-';
+ document.getElementById('currentAddress').textContent = document.getElementById('location_address').value || '-';
+ }