UPdate qr code edit page
This commit is contained in:
@@ -2422,7 +2422,7 @@ def create_qr_code():
|
|||||||
@login_required
|
@login_required
|
||||||
@log_database_operations('qr_code_edit')
|
@log_database_operations('qr_code_edit')
|
||||||
def edit_qr_code(qr_id):
|
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:
|
try:
|
||||||
qr_code = QRCode.query.get_or_404(qr_id)
|
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_address': qr_code.location_address,
|
||||||
'location_event': qr_code.location_event,
|
'location_event': qr_code.location_event,
|
||||||
'project_id': qr_code.project_id,
|
'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
|
# 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_address = request.form['location_address']
|
||||||
qr_code.location_event = request.form.get('location_event', '')
|
qr_code.location_event = request.form.get('location_event', '')
|
||||||
|
|
||||||
# Handle coordinates update
|
# SIMPLIFIED COORDINATE HANDLING - Remove validation requirement
|
||||||
latitude = request.form.get('latitude')
|
latitude = request.form.get('address_latitude') # Changed from 'latitude' to match form
|
||||||
longitude = request.form.get('longitude')
|
longitude = request.form.get('address_longitude') # Changed from 'longitude' to match form
|
||||||
coordinate_accuracy = request.form.get('coordinate_accuracy', 'geocoded')
|
coordinate_accuracy = request.form.get('coordinate_accuracy', 'geocoded')
|
||||||
|
|
||||||
|
# Update coordinates if provided, or keep existing ones
|
||||||
if latitude and longitude:
|
if latitude and longitude:
|
||||||
try:
|
try:
|
||||||
qr_code.address_latitude = float(latitude)
|
qr_code.address_latitude = float(latitude)
|
||||||
@@ -2456,11 +2460,20 @@ def edit_qr_code(qr_id):
|
|||||||
qr_code.coordinate_accuracy = coordinate_accuracy
|
qr_code.coordinate_accuracy = coordinate_accuracy
|
||||||
qr_code.coordinates_updated_date = datetime.utcnow()
|
qr_code.coordinates_updated_date = datetime.utcnow()
|
||||||
except (ValueError, TypeError):
|
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')
|
new_project_id = request.form.get('project_id')
|
||||||
if new_project_id:
|
if new_project_id and new_project_id.strip(): # Check for non-empty string
|
||||||
|
try:
|
||||||
new_project_id = int(new_project_id)
|
new_project_id = int(new_project_id)
|
||||||
project = Project.query.get(new_project_id)
|
project = Project.query.get(new_project_id)
|
||||||
if project and project.active_status:
|
if project and project.active_status:
|
||||||
@@ -2468,7 +2481,12 @@ def edit_qr_code(qr_id):
|
|||||||
else:
|
else:
|
||||||
flash('Selected project is not valid or inactive.', 'error')
|
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())
|
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:
|
else:
|
||||||
|
# Empty or None project_id means unassign from project
|
||||||
qr_code.project_id = None
|
qr_code.project_id = None
|
||||||
|
|
||||||
# Regenerate URL if name changed
|
# 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_url = new_qr_url
|
||||||
qr_code.qr_code_image = new_qr_image
|
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()
|
db.session.commit()
|
||||||
|
|
||||||
# Log changes
|
# Log changes with improved tracking
|
||||||
new_data = {
|
new_data = {
|
||||||
'name': qr_code.name,
|
'name': qr_code.name,
|
||||||
'location': qr_code.location,
|
'location': qr_code.location,
|
||||||
'location_address': qr_code.location_address,
|
'location_address': qr_code.location_address,
|
||||||
'location_event': qr_code.location_event,
|
'location_event': qr_code.location_event,
|
||||||
'project_id': qr_code.project_id,
|
'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 = {}
|
changes = {}
|
||||||
@@ -2500,11 +2526,53 @@ def edit_qr_code(qr_id):
|
|||||||
if old_data[key] != new_data[key]:
|
if old_data[key] != new_data[key]:
|
||||||
changes[key] = {'old': old_data[key], 'new': new_data[key]}
|
changes[key] = {'old': old_data[key], 'new': new_data[key]}
|
||||||
|
|
||||||
|
# Enhanced logging for all changes
|
||||||
if changes:
|
if changes:
|
||||||
logger_handler.logger.info(f"User {session['username']} updated QR code {qr_id}: {json.dumps(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 ""
|
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'))
|
return redirect(url_for('dashboard'))
|
||||||
|
|
||||||
# Get active projects for dropdown
|
# Get active projects for dropdown
|
||||||
|
|||||||
+86
-87
@@ -777,6 +777,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
let originalData = {};
|
let originalData = {};
|
||||||
|
let originalProjectId = {% if qr_code.project_id %}{{ qr_code.project_id }}{% else %}null{% endif %};
|
||||||
|
|
||||||
// Initialize the form when page loads
|
// Initialize the form when page loads
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
@@ -797,25 +798,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function initializeForm() {
|
function initializeForm() {
|
||||||
// Form validation on submit
|
// Form validation on submit - REMOVED COORDINATE UPDATE REQUIREMENT
|
||||||
document.getElementById('editQRForm').addEventListener('submit', function(e) {
|
document.getElementById('editQRForm').addEventListener('submit', function(e) {
|
||||||
if (!validateForm()) {
|
if (!validateForm()) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if changes were made
|
// REMOVED: Check if changes were made - Allow form submission regardless of changes
|
||||||
if (!hasChanges()) {
|
// This enables updates even when only project changes or coordinate updates occur
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show loading state
|
// Show loading state
|
||||||
const submitBtn = document.getElementById('submitBtn');
|
const submitBtn = document.getElementById('submitBtn');
|
||||||
@@ -851,87 +842,56 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function initializeCoordinatesFeature() {
|
function geocodeAddress(address) {
|
||||||
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) {
|
|
||||||
const geocodeBtn = document.getElementById('geocodeBtn');
|
const geocodeBtn = document.getElementById('geocodeBtn');
|
||||||
const statusDiv = document.getElementById('coordinateStatus');
|
const statusDiv = document.getElementById('coordinateStatus');
|
||||||
|
|
||||||
// Show loading state
|
// Show loading state
|
||||||
geocodeBtn.innerHTML = '<span class="loading-spinner"></span> Getting coordinates...';
|
geocodeBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Getting Coordinates...';
|
||||||
geocodeBtn.disabled = true;
|
geocodeBtn.disabled = true;
|
||||||
|
|
||||||
try {
|
showStatus('info', 'Getting coordinates from address...');
|
||||||
const response = await fetch('/api/geocode', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ address: address })
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await response.json();
|
const geocodeUrl = `https://api.opencagedata.com/geocode/v1/json?q=${encodeURIComponent(address)}&key=b0e9dd83c98e4cfebc6a9ef1d83f5a6e&limit=1&countrycode=my&language=en`;
|
||||||
|
|
||||||
if (result.success) {
|
fetch(geocodeUrl)
|
||||||
// Update coordinates
|
.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 = {
|
coordinatesData = {
|
||||||
latitude: result.data.latitude,
|
latitude: lat,
|
||||||
longitude: result.data.longitude,
|
longitude: lng,
|
||||||
accuracy: result.data.accuracy
|
accuracy: confidence >= 8 ? 'high' : confidence >= 5 ? 'medium' : 'low'
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update display
|
|
||||||
updateCoordinatesDisplay();
|
updateCoordinatesDisplay();
|
||||||
|
|
||||||
// Update hidden form fields
|
|
||||||
updateHiddenFields();
|
updateHiddenFields();
|
||||||
|
|
||||||
// Show success message
|
const confidenceText = confidence >= 8 ? 'high' : confidence >= 5 ? 'medium' : 'low';
|
||||||
showStatus('success', result.message);
|
showStatus('success', `Coordinates updated successfully! Accuracy: ${confidenceText}`);
|
||||||
|
|
||||||
|
console.log('✓ Coordinates updated:', coordinatesData);
|
||||||
} else {
|
} else {
|
||||||
showStatus('error', result.message);
|
showStatus('error', 'Could not find coordinates for this address. Please check the address and try again.');
|
||||||
}
|
}
|
||||||
|
})
|
||||||
} catch (error) {
|
.catch(error => {
|
||||||
console.error('Geocoding error:', error);
|
console.error('Geocoding error:', error);
|
||||||
showStatus('error', 'Network error occurred. Please try again.');
|
showStatus('error', 'Failed to get coordinates. Please try again.');
|
||||||
}
|
})
|
||||||
|
.finally(() => {
|
||||||
// Reset button state
|
// Reset button state
|
||||||
geocodeBtn.innerHTML = '<i class="fas fa-search-location"></i> Update Coordinates';
|
geocodeBtn.innerHTML = '<i class="fas fa-search-location"></i> Update Coordinates';
|
||||||
geocodeBtn.disabled = false;
|
geocodeBtn.disabled = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateCoordinatesDisplay() {
|
function updateCoordinatesDisplay() {
|
||||||
@@ -972,6 +932,7 @@
|
|||||||
showStatus('warning', 'Coordinates cleared. Click "Update QR Code" to save changes.');
|
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() {
|
function hasChanges() {
|
||||||
const currentData = {
|
const currentData = {
|
||||||
name: document.getElementById('name').value.trim(),
|
name: document.getElementById('name').value.trim(),
|
||||||
@@ -980,30 +941,35 @@
|
|||||||
location_event: document.getElementById('location_event').value.trim()
|
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];
|
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() {
|
// REMOVED: confirmSaveChanges function - No longer needed since we're allowing all updates
|
||||||
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?'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function showStatus(type, message) {
|
function showStatus(type, message) {
|
||||||
const statusDiv = document.getElementById('coordinateStatus');
|
const statusDiv = document.getElementById('coordinateStatus');
|
||||||
const iconMap = {
|
const iconMap = {
|
||||||
'success': 'fas fa-check-circle',
|
'success': 'fas fa-check-circle',
|
||||||
'error': 'fas fa-exclamation-circle',
|
'error': 'fas fa-exclamation-circle',
|
||||||
'warning': 'fas fa-exclamation-triangle'
|
'warning': 'fas fa-exclamation-triangle',
|
||||||
|
'info': 'fas fa-info-circle'
|
||||||
};
|
};
|
||||||
|
|
||||||
statusDiv.innerHTML = `
|
statusDiv.innerHTML = `
|
||||||
@@ -1080,6 +1046,39 @@
|
|||||||
errorElement.remove();
|
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 || '-';
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user