diff --git a/cleanup_test_files.sh b/cleanup_test_files.sh
new file mode 100755
index 0000000..499112e
--- /dev/null
+++ b/cleanup_test_files.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+# Script de nettoyage des fichiers de test CORS
+
+echo "đź§ą Nettoyage des fichiers de test CORS..."
+
+# Supprimer les fichiers de test
+rm -f test_cors_embed.py
+rm -f test_embed_cors.html
+rm -f cleanup_test_files.sh
+
+echo "✅ Fichiers de test supprimés"
diff --git a/frontend/src/app/pages/agenda/agenda.html b/frontend/src/app/pages/agenda/agenda.html
index 926bb33..8625554 100644
--- a/frontend/src/app/pages/agenda/agenda.html
+++ b/frontend/src/app/pages/agenda/agenda.html
@@ -1,10 +1,6 @@
-
-
@if (isLoading) {
} @else {
-
-
\ No newline at end of file
+
diff --git a/frontend/src/app/pages/agenda/agenda.scss b/frontend/src/app/pages/agenda/agenda.scss
index 1ad8076..e263a6d 100644
--- a/frontend/src/app/pages/agenda/agenda.scss
+++ b/frontend/src/app/pages/agenda/agenda.scss
@@ -10,7 +10,7 @@
grid-template-rows: minmax(100vh, auto);
gap: 0;
// min-height: 100vh;
-
+
&.is-small {
grid-template-columns: 100px 1fr;
}
@@ -220,4 +220,4 @@
.event-edit-panel {
width: 100%;
}
-}
\ No newline at end of file
+}
diff --git a/frontend/src/oedb-types.ts b/frontend/src/oedb-types.ts
index 2edbdab..3ab1db5 100644
--- a/frontend/src/oedb-types.ts
+++ b/frontend/src/oedb-types.ts
@@ -1,6 +1,6 @@
const oedb = {
- presets : {
- what : {
+ presets: {
+ what: {
'community': {
label: 'Événement de base',
description: 'Événement communautaire',
@@ -22,11 +22,11 @@ const oedb = {
description: 'Événement de type Culture ouvert au public',
durationHours: 24,
properties: {
- createdate: { label: 'Createdate', writable: true },
- lastupdate: { label: 'Lastupdate', writable: true },
- start: { label: 'Start', writable: true },
- stop: { label: 'Stop', writable: true },
- type: { label: 'Type', writable: true }
+ createdate: {label: 'Createdate', writable: true},
+ lastupdate: {label: 'Lastupdate', writable: true},
+ start: {label: 'Start', writable: true},
+ stop: {label: 'Stop', writable: true},
+ type: {label: 'Type', writable: true}
}
},
'culture.floss': {
@@ -35,15 +35,15 @@ const oedb = {
category: 'Autre',
description: 'Événement de type Culture Floss',
durationHours: 24,
- properties: {
-}}, 'culture.viparis': {
+ properties: {}
+ }, 'culture.viparis': {
emoji: 'đź“…',
label: 'Évènements organisés par Viparis',
category: 'Autre',
description: 'Événement culturel par Viparis, une entreprise qui gère plusieurs grandes salles en Île de France.',
durationHours: 24,
- properties: {
-}},
+ properties: {}
+ },
// Culture / Arts
@@ -109,8 +109,8 @@ const oedb = {
description: 'Infrastructure de recharge disponible',
durationHours: 300,
properties: {
- "capacity:vehicles": { label: 'Nombre de véhicules qui peuvent actuellement se brancher', writable: true },
- "capacity:vehicles:max": { label: 'Nombre de véhicules maximum à pouvoir se brancher', writable: true }
+ "capacity:vehicles": {label: 'Nombre de véhicules qui peuvent actuellement se brancher', writable: true},
+ "capacity:vehicles:max": {label: 'Nombre de véhicules maximum à pouvoir se brancher', writable: true}
}
},
'traffic.counter.bicycle': {
@@ -162,9 +162,9 @@ const oedb = {
description: 'Accident de la circulation',
durationHours: 6,
properties: {
- severity: { label: 'Gravité', writable: true },
- lanes_closed: { label: 'Voies fermées', writable: true },
- vehicles: { label: 'Nombre de véhicules', writable: true }
+ severity: {label: 'Gravité', writable: true},
+ lanes_closed: {label: 'Voies fermées', writable: true},
+ vehicles: {label: 'Nombre de véhicules', writable: true}
}
},
'traffic.incident': {
@@ -193,9 +193,9 @@ const oedb = {
description: 'Travaux sur la chaussée',
durationHours: 72,
properties: {
- contractor: { label: 'Entreprise', writable: true },
- reason: { label: 'Raison', writable: true },
- lanes_affected: { label: 'Voies impactées', writable: true }
+ contractor: {label: 'Entreprise', writable: true},
+ reason: {label: 'Raison', writable: true},
+ lanes_affected: {label: 'Voies impactées', writable: true}
}
},
'traffic.OperatorAction.NetworkManagement.RoadOrCarriagewayOrLaneManagement': {
@@ -206,7 +206,7 @@ const oedb = {
description: 'Événement de type Traffic OperatorAction NetworkManagement RoadOrCarriagewayOrLaneManagement',
durationHours: 24,
properties: {
- source: { label: 'Source', writable: true },
+ source: {label: 'Source', writable: true},
}
},
@@ -218,7 +218,7 @@ const oedb = {
description: 'Événement de type Traffic OperatorAction NetworkManagement RoadOrCarriagewayOrLaneManagement',
durationHours: 200,
properties: {
- source: { label: 'Source', writable: true },
+ source: {label: 'Source', writable: true},
}
},
'traffic.OperatorAction.NetworkManagement.ReroutingManagement': {
@@ -229,7 +229,7 @@ const oedb = {
description: 'Événement de type Traffic OperatorAction NetworkManagement ReroutingManagement',
durationHours: 200,
properties: {
- source: { label: 'Source', writable: true },
+ source: {label: 'Source', writable: true},
}
},
'traffic.OperatorAction.ConstructionWorks': {
@@ -240,7 +240,7 @@ const oedb = {
description: 'Événement de type Traffic OperatorAction ConstructionWorks',
durationHours: 200,
properties: {
- source: { label: 'Source', writable: true },
+ source: {label: 'Source', writable: true},
}
},
'traffic.OperatorAction.NetworkManagement.SpeedManagement': {
@@ -251,75 +251,75 @@ const oedb = {
description: 'Événement de type Traffic OperatorAction SpeedManagement',
durationHours: 200,
properties: {
- source: { label: 'Source', writable: true },
+ source: {label: 'Source', writable: true},
}
},
// Gestion générale du réseau
-'traffic.OperatorAction.NetworkManagement.GeneralNetworkManagement': {
- emoji: '',
+ 'traffic.OperatorAction.NetworkManagement.GeneralNetworkManagement': {
+ emoji: '',
image: 'static/cone.png',
- label: 'Gestion générale du réseau',
- category: 'Circulation',
- description: 'Événement de type Traffic OperatorAction GeneralNetworkManagement',
- durationHours: 200,
- properties: {
- source: { label: 'Source', writable: true },
- }
-},
-'traffic.closed': {
- emoji: 'â›”',
- label: 'Chaussée fermée',
- category: 'Circulation',
- description: 'Événement de type Traffic Closed',
- durationHours: 200,
- properties: {
- source: { label: 'Source', writable: true },
- }
-},
-'traffic.TrafficElement.GeneralInstructionOrMessageToRoadUsers': {
- emoji: '',
- image: 'static/cone.png',
- label: 'Instruction ou message aux usagers',
- category: 'Circulation',
- description: 'Événement de type Traffic TrafficElement GeneralInstructionOrMessageToRoadUsers',
- durationHours: 200,
- properties: {
- source: { label: 'Source', writable: true },
- }
-},
-'traffic.TrafficElement.Obstruction.GeneralObstruction': {
- emoji: '',
- image: 'static/cone.png',
- label: 'Obstruction générale',
- category: 'Circulation',
- description: 'Événement de type Traffic TrafficElement Obstruction GeneralObstruction',
- durationHours: 200,
- properties: {
- source: { label: 'Source', writable: true },
- }
-},
-'traffic.TrafficElement.Obstruction.InfrastructureDamageObstruction': {
- emoji: 'â›”',
+ label: 'Gestion générale du réseau',
+ category: 'Circulation',
+ description: 'Événement de type Traffic OperatorAction GeneralNetworkManagement',
+ durationHours: 200,
+ properties: {
+ source: {label: 'Source', writable: true},
+ }
+ },
+ 'traffic.closed': {
+ emoji: 'â›”',
+ label: 'Chaussée fermée',
+ category: 'Circulation',
+ description: 'Événement de type Traffic Closed',
+ durationHours: 200,
+ properties: {
+ source: {label: 'Source', writable: true},
+ }
+ },
+ 'traffic.TrafficElement.GeneralInstructionOrMessageToRoadUsers': {
+ emoji: '',
+ image: 'static/cone.png',
+ label: 'Instruction ou message aux usagers',
+ category: 'Circulation',
+ description: 'Événement de type Traffic TrafficElement GeneralInstructionOrMessageToRoadUsers',
+ durationHours: 200,
+ properties: {
+ source: {label: 'Source', writable: true},
+ }
+ },
+ 'traffic.TrafficElement.Obstruction.GeneralObstruction': {
+ emoji: '',
+ image: 'static/cone.png',
+ label: 'Obstruction générale',
+ category: 'Circulation',
+ description: 'Événement de type Traffic TrafficElement Obstruction GeneralObstruction',
+ durationHours: 200,
+ properties: {
+ source: {label: 'Source', writable: true},
+ }
+ },
+ 'traffic.TrafficElement.Obstruction.InfrastructureDamageObstruction': {
+ emoji: 'â›”',
- label: 'Obstruction d\'infrastructure',
- category: 'Circulation',
- description: 'Événement de type Traffic TrafficElement Obstruction InfrastructureDamageObstruction',
- durationHours: 200,
- properties: {
- source: { label: 'Source', writable: true },
- }
-},
-'traffic.TrafficElement.Obstruction.EnvironmentalObstruction': {
- emoji: 'â›”',
+ label: 'Obstruction d\'infrastructure',
+ category: 'Circulation',
+ description: 'Événement de type Traffic TrafficElement Obstruction InfrastructureDamageObstruction',
+ durationHours: 200,
+ properties: {
+ source: {label: 'Source', writable: true},
+ }
+ },
+ 'traffic.TrafficElement.Obstruction.EnvironmentalObstruction': {
+ emoji: 'â›”',
- label: 'Obstruction environnementale',
- category: 'Circulation',
- description: 'Événement de type Traffic TrafficElement Obstruction EnvironmentalObstruction',
- durationHours: 200,
- properties: {
- source: { label: 'Source', writable: true },
- }
-},
+ label: 'Obstruction environnementale',
+ category: 'Circulation',
+ description: 'Événement de type Traffic TrafficElement Obstruction EnvironmentalObstruction',
+ durationHours: 200,
+ properties: {
+ source: {label: 'Source', writable: true},
+ }
+ },
'traffic.obstacle.flood': {
emoji: '🌊',
label: 'Chaussée inondée',
@@ -379,9 +379,9 @@ const oedb = {
description: 'TempĂŞte (vent fort)',
durationHours: 48,
properties: {
- wind_speed: { label: 'Vent moyen (km/h)', writable: true },
- wind_gust: { label: 'Rafales (km/h)', writable: true },
- severity: { label: 'Sévérité', writable: true }
+ wind_speed: {label: 'Vent moyen (km/h)', writable: true},
+ wind_gust: {label: 'Rafales (km/h)', writable: true},
+ severity: {label: 'Sévérité', writable: true}
}
},
'weather.thunder': {
@@ -391,7 +391,7 @@ const oedb = {
description: 'Activité orageuse',
durationHours: 12,
properties: {
- lightning_count: { label: 'Nombre d’éclairs', writable: true }
+ lightning_count: {label: 'Nombre d’éclairs', writable: true}
}
}, 'weather.flood': {
emoji: '🌊',
@@ -400,7 +400,7 @@ const oedb = {
description: 'Inondation',
durationHours: 24,
properties: {
- flood_level: { label: 'Niveau d\'inondation', writable: true }
+ flood_level: {label: 'Niveau d\'inondation', writable: true}
}
},
'weather.snow': {
@@ -410,7 +410,7 @@ const oedb = {
description: 'Neige',
durationHours: 12,
properties: {
- snow_level: { label: 'Niveau de neige', writable: true }
+ snow_level: {label: 'Niveau de neige', writable: true}
}
},
'weather.earthquake': {
@@ -420,8 +420,8 @@ const oedb = {
description: 'Séisme',
durationHours: 6,
properties: {
- magnitude: { label: 'Magnitude (Mw)', writable: true },
- depth_km: { label: 'Profondeur (km)', writable: true }
+ magnitude: {label: 'Magnitude (Mw)', writable: true},
+ depth_km: {label: 'Profondeur (km)', writable: true}
}
},
@@ -433,8 +433,8 @@ const oedb = {
description: 'Interruption d\'itinéraire',
durationHours: 200,
properties: {
- reason: { label: 'Raison', writable: true },
- route: { label: 'Itinéraire', writable: true },
+ reason: {label: 'Raison', writable: true},
+ route: {label: 'Itinéraire', writable: true},
}
},
@@ -445,8 +445,8 @@ const oedb = {
description: 'Mauvais sens de circulation',
durationHours: 200,
properties: {
- reason: { label: 'Raison', writable: true },
- route: { label: 'Itinéraire', writable: true },
+ reason: {label: 'Raison', writable: true},
+ route: {label: 'Itinéraire', writable: true},
}
},
@@ -457,7 +457,7 @@ const oedb = {
description: 'Contestation d\'itinéraire',
durationHours: 200,
properties: {
- route: { label: 'Itinéraire', writable: true },
+ route: {label: 'Itinéraire', writable: true},
}
}
// ici ajouter d'autres catégories d'évènements à suggérer
diff --git a/oedb/middleware/headers.py b/oedb/middleware/headers.py
index 7d4f297..58fd108 100644
--- a/oedb/middleware/headers.py
+++ b/oedb/middleware/headers.py
@@ -2,6 +2,7 @@
Middleware components for the OpenEventDatabase.
"""
+import falcon
from oedb.utils.logging import logger
class HeaderMiddleware:
@@ -9,6 +10,21 @@ class HeaderMiddleware:
Middleware that adds standard headers to all responses.
"""
+ def process_request(self, req, resp, resource, params):
+ """
+ Handle preflight OPTIONS requests for CORS.
+
+ Args:
+ req: The request object.
+ resp: The response object.
+ resource: The resource object.
+ params: The request parameters.
+ """
+ if req.method == 'OPTIONS':
+ logger.debug("Handling CORS preflight request")
+ resp.status = falcon.HTTP_200
+ return True # Skip further processing
+
def process_response(self, req, resp, resource, params):
"""
Add standard headers to the response.
@@ -21,7 +37,15 @@ class HeaderMiddleware:
"""
logger.debug("Adding standard headers to response")
resp.set_header('X-Powered-By', 'OpenEventDatabase')
+
+ # CORS headers - Configuration optimisée pour embed.js
resp.set_header('Access-Control-Allow-Origin', '*')
- resp.set_header('Access-Control-Allow-Headers', 'X-Requested-With')
- resp.set_header('Access-Control-Allow-Headers', 'Content-Type')
- resp.set_header('Access-Control-Allow-Methods','GET, POST, PUT, DELETE, OPTIONS')
\ No newline at end of file
+ resp.set_header('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Authorization, Accept, Origin, User-Agent, Referer')
+ resp.set_header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS, HEAD')
+ resp.set_header('Access-Control-Allow-Credentials', 'false')
+ resp.set_header('Access-Control-Max-Age', '86400') # 24 hours
+ resp.set_header('Access-Control-Expose-Headers', 'Content-Length, Content-Type, Date, Server, X-Powered-By')
+
+ # Headers supplémentaires pour embed.js
+ resp.set_header('Vary', 'Origin')
+ resp.set_header('Cache-Control', 'public, max-age=300') # Cache de 5 minutes pour les requĂŞtes embed
\ No newline at end of file
diff --git a/test_cors_embed.py b/test_cors_embed.py
new file mode 100644
index 0000000..ecc9d45
--- /dev/null
+++ b/test_cors_embed.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python3
+"""
+Script de test pour vérifier la configuration CORS avec embed.js
+"""
+
+import requests
+import json
+
+def test_cors_headers():
+ """Test des headers CORS pour l'API OEDB"""
+
+ # URL de l'API (Ă adapter selon votre configuration)
+ api_url = "http://localhost:8080/events"
+
+ print("🔍 Test de la configuration CORS pour embed.js")
+ print("=" * 50)
+
+ # Test 1: RequĂŞte GET simple
+ print("\n1. Test requĂŞte GET simple...")
+ try:
+ response = requests.get(api_url, timeout=10)
+ print(f" Status: {response.status_code}")
+
+ # Vérifier les headers CORS
+ cors_headers = {
+ 'Access-Control-Allow-Origin': response.headers.get('Access-Control-Allow-Origin'),
+ 'Access-Control-Allow-Headers': response.headers.get('Access-Control-Allow-Headers'),
+ 'Access-Control-Allow-Methods': response.headers.get('Access-Control-Allow-Methods'),
+ 'Access-Control-Max-Age': response.headers.get('Access-Control-Max-Age'),
+ 'Access-Control-Expose-Headers': response.headers.get('Access-Control-Expose-Headers')
+ }
+
+ print(" Headers CORS:")
+ for header, value in cors_headers.items():
+ status = "✅" if value else "❌"
+ print(f" {status} {header}: {value}")
+
+ except requests.exceptions.RequestException as e:
+ print(f" ❌ Erreur de connexion: {e}")
+ return False
+
+ # Test 2: RequĂŞte OPTIONS (preflight)
+ print("\n2. Test requĂŞte OPTIONS (preflight)...")
+ try:
+ headers = {
+ 'Origin': 'https://example.com',
+ 'Access-Control-Request-Method': 'GET',
+ 'Access-Control-Request-Headers': 'Content-Type'
+ }
+
+ response = requests.options(api_url, headers=headers, timeout=10)
+ print(f" Status: {response.status_code}")
+
+ if response.status_code == 200:
+ print(" ✅ Requête preflight réussie")
+ else:
+ print(" ❌ Requête preflight échouée")
+
+ except requests.exceptions.RequestException as e:
+ print(f" ❌ Erreur de connexion: {e}")
+ return False
+
+ # Test 3: Simulation d'une requĂŞte depuis embed.js
+ print("\n3. Test simulation embed.js...")
+ try:
+ headers = {
+ 'Origin': 'https://example.com',
+ 'User-Agent': 'Mozilla/5.0 (compatible; OEDB-Embed/1.0)',
+ 'Referer': 'https://example.com/page-with-embed'
+ }
+
+ response = requests.get(api_url, headers=headers, timeout=10)
+ print(f" Status: {response.status_code}")
+
+ # Vérifier que la réponse contient des données
+ if response.status_code == 200:
+ try:
+ data = response.json()
+ print(f" ✅ Données reçues: {len(data.get('features', []))} événements")
+ except json.JSONDecodeError:
+ print(" ⚠️ Réponse reçue mais pas de JSON valide")
+ else:
+ print(f" ❌ Erreur HTTP: {response.status_code}")
+
+ except requests.exceptions.RequestException as e:
+ print(f" ❌ Erreur de connexion: {e}")
+ return False
+
+ print("\n" + "=" * 50)
+ print("✅ Tests CORS terminés")
+ return True
+
+if __name__ == "__main__":
+ test_cors_headers()
diff --git a/test_embed_cors.html b/test_embed_cors.html
new file mode 100644
index 0000000..f00a184
--- /dev/null
+++ b/test_embed_cors.html
@@ -0,0 +1,180 @@
+
+
+
+
+
+
Test OEDB Embed avec CORS
+
+
+
+
đź§Ş Test OEDB Embed avec Configuration CORS
+
+
+
Configuration du Test
+
+ Chargement de la configuration...
+
+
+
+
+
Test de Connexion CORS
+
+ Test en cours...
+
+
+
+
+
+
Intégration OEDB Embed
+
Configuration utilisée :
+
+
+
+
+ Chargement du widget OEDB...
+
+
+
+
+
+
Logs de Debug
+
+
🚀 Initialisation du test...
+
+
+
+
+
+
+
+
+