up traffic

This commit is contained in:
Tykayn 2025-09-27 01:31:36 +02:00 committed by tykayn
parent 11cd3236c5
commit 3ec22cbe3b
4 changed files with 321 additions and 58 deletions

View file

@ -52,27 +52,47 @@ class DemoResource:
# Set content type to HTML # Set content type to HTML
resp.content_type = 'text/html' resp.content_type = 'text/html'
# Fetch the event data from the API # Fetch the event data from the OEDB API
logger.info(f"Fetching event data from API for event ID: {id}")
response = requests.get(f'https://api.openeventdatabase.org/event/{id}') response = requests.get(f'https://api.openeventdatabase.org/event/{id}')
if response.status_code != 200: if response.status_code != 200:
logger.error(f"API returned status {response.status_code} for event {id}")
resp.status = falcon.HTTP_404 resp.status = falcon.HTTP_404
resp.text = f"Event with ID {id} not found" resp.text = f"Event with ID {id} not found on API"
return return
event_data = response.json() event_data = response.json()
logger.info(f"Successfully retrieved event data for {id}: {type(event_data)}")
# Validate event data structure
if not isinstance(event_data, dict):
logger.error(f"Invalid event data type: {type(event_data)}")
resp.status = falcon.HTTP_500
resp.text = "Invalid event data format received from API"
return
if 'properties' not in event_data:
logger.error(f"Event data missing 'properties': {event_data}")
resp.status = falcon.HTTP_500
resp.text = "Invalid event data structure - missing properties"
return
# Render the template with the event data # Render the template with the event data
template = self.jinja_env.get_template('edit.html') template = self.jinja_env.get_template('edit.html')
html = template.render( html = template.render(
id=id, id=id,
event_data=event_data event_data=event_data # Pass Python object directly, let Jinja2 handle JSON conversion
) )
# Set the response body and status # Set the response body and status
resp.text = html resp.text = html
resp.status = falcon.HTTP_200 resp.status = falcon.HTTP_200
logger.success(f"Successfully processed GET request to /demo/edit for event ID: {id}") logger.success(f"Successfully processed GET request to /demo/edit for event ID: {id}")
except requests.RequestException as e:
logger.error(f"Error fetching event data from API: {e}")
resp.status = falcon.HTTP_500
resp.text = f"Error fetching event data: {str(e)}"
except Exception as e: except Exception as e:
logger.error(f"Error processing GET request to /demo/edit: {e}") logger.error(f"Error processing GET request to /demo/edit: {e}")
resp.status = falcon.HTTP_500 resp.status = falcon.HTTP_500

View file

@ -57,6 +57,9 @@ function populateForm() {
console.log('✅ Données événement validées, remplissage du formulaire...'); console.log('✅ Données événement validées, remplissage du formulaire...');
// Remplir le tableau des propriétés
populatePropertiesTable(eventData.properties);
const properties = eventData.properties; const properties = eventData.properties;
// Set form values // Set form values
@ -95,23 +98,86 @@ function populateForm() {
zoom: 10 zoom: 10
}); });
} }
// Initialiser l'autocomplétion pour le champ "what"
const whatInput = document.getElementById('what');
if (whatInput && window.initializeEventTypeAutocomplete) {
initializeEventTypeAutocomplete(whatInput);
}
}
// Function to populate the properties table
function populatePropertiesTable(properties) {
const tableBody = document.getElementById('propertiesTableBody');
if (!tableBody) return;
// Clear existing rows
tableBody.innerHTML = '';
// Sort properties alphabetically
const sortedProperties = Object.keys(properties).sort();
sortedProperties.forEach(key => {
const value = properties[key];
const row = document.createElement('tr');
// Determine value type and format
let displayValue;
let valueType;
if (value === null) {
displayValue = '<em style="color: #999;">null</em>';
valueType = 'null';
} else if (typeof value === 'object') {
displayValue = `<pre style="margin: 0; font-size: 12px;">${JSON.stringify(value, null, 2)}</pre>`;
valueType = 'object';
} else if (typeof value === 'string' && value.match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/)) {
displayValue = value + ` <small style="color: #666;">(${new Date(value).toLocaleString()})</small>`;
valueType = 'datetime';
} else if (typeof value === 'string' && value.startsWith('http')) {
displayValue = `<a href="${value}" target="_blank">${value}</a>`;
valueType = 'url';
} else {
displayValue = String(value);
valueType = typeof value;
}
row.innerHTML = `
<td style="padding: 6px; border-bottom: 1px solid #eee; font-weight: bold; color: #333;">${key}</td>
<td style="padding: 6px; border-bottom: 1px solid #eee; word-break: break-word;">${displayValue}</td>
<td style="padding: 6px; border-bottom: 1px solid #eee; color: #666; font-size: 12px;">${valueType}</td>
`;
// Add alternating row colors
if (tableBody.children.length % 2 === 0) {
row.style.backgroundColor = '#f9f9f9';
}
tableBody.appendChild(row);
});
} }
// Attendre que les données soient disponibles avant de peupler le formulaire // Attendre que les données soient disponibles avant de peupler le formulaire
function initializeForm() { function initializeForm(retryCount = 0) {
if (typeof window.eventDataJson !== 'undefined') { console.log(`🔄 Tentative d'initialisation ${retryCount + 1}/10`);
if (typeof window.eventData !== 'undefined' && window.eventData !== null) {
console.log('📄 Données disponibles, initialisation du formulaire...'); console.log('📄 Données disponibles, initialisation du formulaire...');
populateForm(); populateForm();
} else if (retryCount < 10) {
console.log('⏳ En attente des données, nouvelle tentative dans 200ms...');
setTimeout(() => initializeForm(retryCount + 1), 200);
} else { } else {
console.log('⏳ En attente des données, nouvelle tentative dans 100ms...'); console.error('❌ Timeout: Impossible de récupérer les données après 10 tentatives');
setTimeout(initializeForm, 100); showResult('Impossible de charger les données de l\'événement après plusieurs tentatives', 'error');
} }
} }
// Démarrer l'initialisation // Démarrer l'initialisation
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
console.log('🚀 DOM chargé, démarrage de l\'initialisation...'); console.log('🚀 DOM chargé, démarrage de l\'initialisation...');
initializeForm(); // Attendre un peu pour laisser le temps au script du template de s'exécuter
setTimeout(() => initializeForm(), 100);
}); });
// Add marker on map click // Add marker on map click
@ -119,6 +185,36 @@ map.on('click', function(e) {
marker.setLngLat(e.lngLat).addTo(map); marker.setLngLat(e.lngLat).addTo(map);
}); });
// Add functionality for swapping coordinates button
document.addEventListener('DOMContentLoaded', function() {
const swapButton = document.getElementById('swapCoordinatesButton');
if (swapButton) {
swapButton.addEventListener('click', function() {
if (!marker || !marker.getLngLat()) {
showResult('Veuillez d\'abord placer un marqueur sur la carte', 'error');
return;
}
const currentLngLat = marker.getLngLat();
const swappedLngLat = [currentLngLat.lat, currentLngLat.lng];
// Update marker position
marker.setLngLat(swappedLngLat);
// Show confirmation message
showResult(`Coordonnées inversées: ${currentLngLat.lng.toFixed(6)}, ${currentLngLat.lat.toFixed(6)}${swappedLngLat[0].toFixed(6)}, ${swappedLngLat[1].toFixed(6)}`, 'success');
// Auto-hide success message after 3 seconds
setTimeout(() => {
const resultElement = document.getElementById('result');
if (resultElement && resultElement.className === 'success') {
resultElement.style.display = 'none';
}
}, 3000);
});
}
});
// Function to show result message // Function to show result message
function showResult(message, type) { function showResult(message, type) {
const resultElement = document.getElementById('result'); const resultElement = document.getElementById('result');
@ -180,8 +276,8 @@ document.getElementById('eventForm').addEventListener('submit', function(e) {
event.properties.where = where; event.properties.where = where;
} }
// Submit event to API // Submit event to OEDB API
fetch(`/event/${eventId}`, { fetch(`https://api.openeventdatabase.org/event/${eventId}`, {
method: 'PUT', method: 'PUT',
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
@ -198,14 +294,39 @@ document.getElementById('eventForm').addEventListener('submit', function(e) {
} }
}) })
.then(data => { .then(data => {
showResult(`Event updated successfully with ID: ${data.id}`, 'success'); console.log('📅 Réponse API de modification:', data);
// Extract event ID from response (handle different response structures)
let eventId = null;
if (data.properties && data.properties.id) {
eventId = data.properties.id;
} else if (data.id) {
eventId = data.id;
} else if (typeof data === 'string') {
eventId = data;
} else {
// Fallback: use the eventId from the form
eventId = document.getElementById('eventId').value;
}
console.log('🆔 ID événement pour les liens:', eventId);
showResult(`✅ Événement mis à jour avec succès !${eventId ? ` ID: ${eventId}` : ''}`, 'success');
// Add link to view the event // Add link to view the event
const resultElement = document.getElementById('result'); const resultElement = document.getElementById('result');
resultElement.innerHTML += `<p><a href="/event/${data.id}" >View Event</a> | <a href="/demo">Back to Map</a></p>`; let linksHtml = '<p>';
if (eventId) {
linksHtml += `<a href="/demo/by_id/${eventId}" >Voir l'événement</a> | `;
}
linksHtml += '<a href="/demo">Retour à la carte</a></p>';
resultElement.innerHTML += linksHtml;
}) })
.catch(error => { .catch(error => {
showResult(`Error: ${error.message}`, 'error'); console.error('❌ Erreur lors de la modification:', error);
showResult(`❌ Erreur lors de la modification: ${error.message}`, 'error');
}); });
}); });

View file

@ -140,11 +140,11 @@ document.addEventListener('DOMContentLoaded', function () {
} }
// Set up form submission after DOM is loaded // Set up form submission after DOM is loaded
const reportForm = document.getElementById('trafficForm'); const reportForm = document.getElementById('reportForm');
if (reportForm) { if (reportForm) {
reportForm.addEventListener('submit', submitReport); reportForm.addEventListener('submit', submitReport);
} else { } else {
console.warn('Traffic form not found in DOM'); console.warn('Report form not found in DOM');
} }
} }
@ -251,13 +251,26 @@ document.addEventListener('DOMContentLoaded', function () {
} }
} }
// Submit the event to the API // Submit the event to the OEDB API
const response = await fetch('/event', { const response = await fetch('https://api.openeventdatabase.org/event', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}, },
body: JSON.stringify(eventData) body: JSON.stringify({
type: 'Feature',
geometry: eventData.geometry,
properties: {
type: eventData.type,
what: eventData.what,
label: eventData.label,
description: eventData.description,
start: eventData.start,
stop: eventData.stop,
...(eventData.source && { source: eventData.source }),
...(eventData.media && { media: eventData.media })
}
})
}); });
if (!response.ok) { if (!response.ok) {
@ -267,8 +280,44 @@ document.addEventListener('DOMContentLoaded', function () {
const data = await response.json(); const data = await response.json();
// Show success message // Extract event ID from response (handle different response structures)
resultElement.textContent = `Report submitted successfully! Event ID: ${data.id}`; let eventId = null;
if (data.properties && data.properties.id) {
eventId = data.properties.id;
} else if (data.id) {
eventId = data.id;
} else if (typeof data === 'string') {
eventId = data;
}
console.log('📅 Réponse API complète:', data);
console.log('🆔 ID événement extrait:', eventId);
// Show success message with links
let successHtml = `
<div style="color: #28a745; padding: 15px; background: #d4edda; border: 1px solid #c3e6cb; border-radius: 4px;">
<i class="fas fa-check-circle"></i>
<strong> Événement créé avec succès !</strong>
`;
if (eventId) {
successHtml += `<br>ID: ${eventId}<br><br>
<a href="/demo/by_id/${eventId}" style="color: #0078ff; text-decoration: none; font-weight: bold;">
<i class="fas fa-eye"></i> Voir l'événement
</a>
|`;
} else {
successHtml += `<br><small>ID d'événement non disponible dans la réponse</small><br><br>`;
}
successHtml += `
<a href="/demo" style="color: #0078ff; text-decoration: none; font-weight: bold;">
<i class="fas fa-map"></i> Retour à la carte
</a>
</div>
`;
resultElement.innerHTML = successHtml;
resultElement.className = 'success'; resultElement.className = 'success';
// Reset the form // Reset the form
@ -280,11 +329,29 @@ document.addEventListener('DOMContentLoaded', function () {
previewContainer.style.display = 'none'; previewContainer.style.display = 'none';
} }
// Remove marker from map
if (marker) {
marker.remove();
marker = null;
currentPosition = null;
}
// Initialize the form again // Initialize the form again
initForm(); initForm();
// Re-validate form to disable submit button
validateForm();
} catch (error) { } catch (error) {
console.error('❌ Erreur lors de la création d\'événement:', error);
// Show error message // Show error message
resultElement.textContent = `Error: ${error.message}`; resultElement.innerHTML = `
<div style="color: #dc3545; padding: 15px; background: #f8d7da; border: 1px solid #f5c6cb; border-radius: 4px;">
<i class="fas fa-exclamation-triangle"></i>
<strong> Erreur lors de la création de l'événement</strong>
<br><small>${error.message}</small>
</div>
`;
resultElement.className = 'error'; resultElement.className = 'error';
} }
} }
@ -325,7 +392,7 @@ document.addEventListener('DOMContentLoaded', function () {
// Setup form validation // Setup form validation
function setupFormValidation() { function setupFormValidation() {
const form = document.getElementById('trafficForm'); const form = document.getElementById('reportForm');
if (!form) return; if (!form) return;
// Get all form fields that need validation // Get all form fields that need validation
@ -359,7 +426,7 @@ document.addEventListener('DOMContentLoaded', function () {
} }
// Initial validation // Initial validation
validateForm(); // validateForm();
} }
@ -376,7 +443,7 @@ function clearFieldError(element) {
} }
// Validate the entire form // Validate the entire form
function validateForm() { function validateForm() {
const form = document.getElementById('trafficForm'); const form = document.getElementById('reportForm');
const submitButton = document.getElementById('report_issue_button'); const submitButton = document.getElementById('report_issue_button');
if (!form || !submitButton) { if (!form || !submitButton) {

View file

@ -115,17 +115,49 @@
{% block scripts %} {% block scripts %}
<script> <script>
// Event data from API - corriger le double-encodage // Event data from API - using proper JSON serialization
window.eventData = null; window.eventData = null;
try {
// Utiliser directement les données JSON sans double-encodage
window.eventData = {{ event_data|safe }};
console.log('✅ Données événement chargées:', window.eventData);
} catch (error) {
console.error('❌ Erreur de chargement des données événement:', error);
console.error('Données brutes JSON:', '{{ event_data|safe }}');
// Afficher une erreur à l'utilisateur try {
// Use Jinja2's tojson filter for proper JSON encoding
window.eventData = {{ event_data|tojson }};
console.log('✅ Données événement chargées via tojson:', window.eventData);
if (!window.eventData || window.eventData === null) {
throw new Error('Données d\'événement nulles depuis le template');
}
} catch (error) {
console.error('❌ Erreur de chargement des données depuis le template:', error);
// Fallback: try to fetch from API directly
const eventId = document.getElementById('eventId')?.value;
if (eventId) {
console.log('🔄 Fallback: Récupération directe depuis l\'API...');
fetch(`https://api.openeventdatabase.org/event/${eventId}`)
.then(response => {
if (!response.ok) {
throw new Error(`API returned ${response.status}: ${response.statusText}`);
}
return response.json();
})
.then(data => {
console.log('✅ Données récupérées depuis l\'API (fallback):', data);
window.eventData = data;
// Trigger form population
if (typeof populateForm === 'function') {
populateForm();
} else {
// Wait for edit.js to load
setTimeout(() => {
if (typeof populateForm === 'function') {
populateForm();
}
}, 100);
}
})
.catch(apiError => {
console.error('❌ Erreur API également:', apiError);
// Show error to user
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
const resultElement = document.getElementById('result'); const resultElement = document.getElementById('result');
if (resultElement) { if (resultElement) {
@ -133,13 +165,36 @@
<div style="color: #dc3545; padding: 15px; background: #f8d7da; border: 1px solid #f5c6cb; border-radius: 4px;"> <div style="color: #dc3545; padding: 15px; background: #f8d7da; border: 1px solid #f5c6cb; border-radius: 4px;">
<i class="fas fa-exclamation-triangle"></i> <i class="fas fa-exclamation-triangle"></i>
<strong>Erreur de chargement:</strong> Impossible de charger les données de l'événement. <strong>Erreur de chargement:</strong> Impossible de charger les données de l'événement.
<br><small>Erreur technique: ${error.message}</small> <br><small>Erreur template: ${error.message}</small>
<br><small>Erreur API: ${apiError.message}</small>
<br><br>
<a href="/demo" class="button">Retour à la carte</a>
</div>
`;
resultElement.style.display = 'block';
}
});
});
} else {
console.error('❌ Aucun ID d\'événement trouvé pour le fallback API');
// Show error immediately
document.addEventListener('DOMContentLoaded', function() {
const resultElement = document.getElementById('result');
if (resultElement) {
resultElement.innerHTML = `
<div style="color: #dc3545; padding: 15px; background: #f8d7da; border: 1px solid #f5c6cb; border-radius: 4px;">
<i class="fas fa-exclamation-triangle"></i>
<strong>Erreur:</strong> ID d'événement manquant et impossible de charger les données.
<br><br>
<a href="/demo" class="button">Retour à la carte</a>
</div> </div>
`; `;
resultElement.style.display = 'block'; resultElement.style.display = 'block';
} }
}); });
} }
}
</script> </script>
<script src="/static/edit.js"></script> <script src="/static/edit.js"></script>
{% endblock %} {% endblock %}