diff --git a/doc/SEARCH_ENDPOINT.md b/doc/api_search.md
similarity index 100%
rename from doc/SEARCH_ENDPOINT.md
rename to doc/api_search.md
diff --git a/extractors/SNCF_TRAVAUX_IMPLEMENTATION.md b/doc/extractor_sncf.md
similarity index 100%
rename from extractors/SNCF_TRAVAUX_IMPLEMENTATION.md
rename to doc/extractor_sncf.md
diff --git a/extractors/osm_cal.py b/extractors/osm_cal.py
index 83bce59..2bd0d3a 100755
--- a/extractors/osm_cal.py
+++ b/extractors/osm_cal.py
@@ -284,6 +284,7 @@ def event_exists(db, properties):
Returns:
bool: True if the event exists, False otherwise.
"""
+ print('event: ', properties)
try:
cur = db.cursor()
@@ -348,6 +349,7 @@ def submit_event(event):
cur = db.cursor()
geometry = json.dumps(event['geometry'])
+ print('event: ', event)
# Insert the geometry into the geo table
cur.execute("""
INSERT INTO geo
@@ -361,20 +363,56 @@ def submit_event(event):
hash_result = cur.fetchone()
if hash_result is None:
- # If the hash is None, get it from the database
+ # If the hash is None, check if the geometry already exists in the database
cur.execute("""
- SELECT md5(st_asewkt(geom)),
- ST_IsValid(geom),
- ST_IsValidReason(geom) from (SELECT st_geomfromgeojson(%s) as geom) as g;
+ SELECT hash FROM geo
+ WHERE hash = md5(st_astext(st_setsrid(st_geomfromgeojson(%s),4326)));
""", (geometry,))
- hash_result = cur.fetchone()
-
- if hash_result is None or (len(hash_result) > 1 and not hash_result[1]):
- logger.error(f"Invalid geometry for event: {properties.get('label')}")
- db.close()
- return False
-
- geo_hash = hash_result[0]
+ existing_hash = cur.fetchone()
+
+ if existing_hash:
+ # Geometry already exists in the database, use its hash
+ geo_hash = existing_hash[0]
+ logger.info(f"Using existing geometry with hash: {geo_hash}")
+ else:
+ # Geometry doesn't exist, try to insert it directly
+ cur.execute("""
+ SELECT md5(st_astext(geom)) as hash,
+ ST_IsValid(geom),
+ ST_IsValidReason(geom) from (SELECT st_setsrid(st_geomfromgeojson(%s),4326) as geom) as g;
+ """, (geometry,))
+ hash_result = cur.fetchone()
+
+ if hash_result is None or not hash_result[1]:
+ logger.error(f"Invalid geometry for event: {properties.get('label')}")
+ if hash_result and len(hash_result) > 2:
+ logger.error(f"Reason: {hash_result[2]}")
+ db.close()
+ return False
+
+ geo_hash = hash_result[0]
+
+ # Now insert the geometry explicitly
+ cur.execute("""
+ INSERT INTO geo (geom, hash, geom_center)
+ VALUES (
+ st_setsrid(st_geomfromgeojson(%s),4326),
+ %s,
+ st_centroid(st_setsrid(st_geomfromgeojson(%s),4326))
+ )
+ ON CONFLICT (hash) DO NOTHING;
+ """, (geometry, geo_hash, geometry))
+
+ # Verify the geometry was inserted
+ cur.execute("SELECT 1 FROM geo WHERE hash = %s", (geo_hash,))
+ if cur.fetchone() is None:
+ logger.error(f"Failed to insert geometry with hash: {geo_hash}")
+ db.close()
+ return False
+
+ logger.info(f"Inserted new geometry with hash: {geo_hash}")
+ else:
+ geo_hash = hash_result[0]
# Determine the bounds for the time range
bounds = '[]' if properties['start'] == properties['stop'] else '[)'
diff --git a/oedb/resources/demo.py b/oedb/resources/demo.py
index 82c6bba..159b321 100644
--- a/oedb/resources/demo.py
+++ b/oedb/resources/demo.py
@@ -505,6 +505,7 @@ class DemoResource:
@@ -958,6 +959,771 @@ class DemoResource:
resp.status = falcon.HTTP_500
resp.text = f"Error: {str(e)}"
+ def on_get_search(self, req, resp):
+ """
+ Handle GET requests to the /demo/search endpoint.
+ Returns an HTML page with a form for searching events and displaying results.
+
+ Args:
+ req: The request object.
+ resp: The response object.
+ """
+ logger.info("Processing GET request to /demo/search")
+
+ try:
+ # Set content type to HTML
+ resp.content_type = 'text/html'
+
+ # Create HTML response with search form
+ html = """
+
+
+
+
+
+ Search Events - OpenEventDatabase
+
+
+
+
+
+
+
+
+
+
+
+
+ """
+
+ # Set the response body and status
+ resp.text = html
+ resp.status = falcon.HTTP_200
+ logger.success("Successfully processed GET request to /demo/search")
+ except Exception as e:
+ logger.error(f"Error processing GET request to /demo/search: {e}")
+ resp.status = falcon.HTTP_500
+ resp.text = f"Error: {str(e)}"
+
def on_get_map_by_what(self, req, resp):
"""
Handle GET requests to the /demo/map-by-what endpoint.
diff --git a/oedb/utils/db.py b/oedb/utils/db.py
index 5acf7e9..da2fc72 100644
--- a/oedb/utils/db.py
+++ b/oedb/utils/db.py
@@ -10,15 +10,19 @@ from oedb.utils.logging import logger
def load_env_from_file():
"""
- Load environment variables from .env file.
+ Load environment variables from .env file at the project root directory.
This ensures that database connection parameters are properly set.
Returns:
bool: True if the .env file exists and was loaded, False otherwise.
"""
- if os.path.exists('.env'):
- logger.info("Loading environment variables from .env file...")
- with open('.env', 'r') as f:
+ # Determine the project root directory (parent directory of the oedb package)
+ project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '../..'))
+ env_file_path = os.path.join(project_root, '.env')
+
+ if os.path.exists(env_file_path):
+ logger.info(f"Loading environment variables from {env_file_path}...")
+ with open(env_file_path, 'r') as f:
for line in f:
line = line.strip()
if line and not line.startswith('#'):
@@ -26,7 +30,7 @@ def load_env_from_file():
os.environ[key] = value
return True
else:
- logger.warning(".env file not found")
+ logger.warning(f".env file not found at {env_file_path}")
return False
def db_connect():
diff --git a/server_config/SYSTEMD_SERVICE_INSTALLATION.md b/server_config/systemd_service_installation.md
similarity index 100%
rename from server_config/SYSTEMD_SERVICE_INSTALLATION.md
rename to server_config/systemd_service_installation.md
diff --git a/test_env_path.py b/test_env_path.py
new file mode 100755
index 0000000..0e0d358
--- /dev/null
+++ b/test_env_path.py
@@ -0,0 +1,153 @@
+#!/usr/bin/env python3
+"""
+Test script to verify that the load_env_from_file function correctly finds
+the .env file at the project root directory, regardless of the current working directory.
+"""
+
+import os
+import sys
+import shutil
+import tempfile
+import subprocess
+
+# Add the parent directory to the path so we can import from oedb
+sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
+
+from oedb.utils.db import load_env_from_file
+from oedb.utils.logging import logger
+
+def test_load_env_from_file_in_root():
+ """
+ Test the load_env_from_file function when run from the project root directory.
+ """
+ print("\n=== Testing load_env_from_file from project root ===")
+
+ # Backup the .env file if it exists
+ env_exists = os.path.exists('.env')
+ if env_exists:
+ print("Backing up existing .env file...")
+ shutil.copy('.env', '.env.backup')
+
+ # Create a test .env file
+ print("Creating test .env file at project root...")
+ with open('.env', 'w') as f:
+ f.write("TEST_VAR_ROOT=test_value_root\n")
+
+ # Test the function
+ print("Testing load_env_from_file()...")
+ result = load_env_from_file()
+ print(f"load_env_from_file() returned: {result}")
+ print(f"TEST_VAR_ROOT environment variable: {os.getenv('TEST_VAR_ROOT')}")
+
+ # Clean up
+ os.remove('.env')
+
+ # Restore the original .env file if it existed
+ if env_exists:
+ print("Restoring original .env file...")
+ shutil.move('.env.backup', '.env')
+
+def test_load_env_from_file_in_subdir():
+ """
+ Test the load_env_from_file function when run from a subdirectory.
+ """
+ print("\n=== Testing load_env_from_file from a subdirectory ===")
+
+ # Create a temporary subdirectory
+ with tempfile.TemporaryDirectory(dir='.') as temp_dir:
+ print(f"Created temporary subdirectory: {temp_dir}")
+
+ # Backup the .env file if it exists
+ env_exists = os.path.exists('.env')
+ if env_exists:
+ print("Backing up existing .env file...")
+ shutil.copy('.env', '.env.backup')
+
+ # Create a test .env file at the project root
+ print("Creating test .env file at project root...")
+ with open('.env', 'w') as f:
+ f.write("TEST_VAR_SUBDIR=test_value_subdir\n")
+
+ # Create a test script in the subdirectory
+ test_script_path = os.path.join(temp_dir, 'test_script.py')
+ print(f"Creating test script at {test_script_path}...")
+ with open(test_script_path, 'w') as f:
+ f.write("""#!/usr/bin/env python3
+import os
+import sys
+
+# Add the project root to the path
+sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
+
+from oedb.utils.db import load_env_from_file
+
+# Test the function
+result = load_env_from_file()
+print(f"load_env_from_file() returned: {result}")
+print(f"TEST_VAR_SUBDIR environment variable: {os.getenv('TEST_VAR_SUBDIR')}")
+""")
+
+ # Make the test script executable
+ os.chmod(test_script_path, 0o755)
+
+ # Run the test script from the subdirectory
+ print(f"Running test script from {temp_dir}...")
+ subprocess.run([sys.executable, test_script_path], cwd=temp_dir)
+
+ # Clean up
+ os.remove('.env')
+
+ # Restore the original .env file if it existed
+ if env_exists:
+ print("Restoring original .env file...")
+ shutil.move('.env.backup', '.env')
+
+def test_osm_cal_script():
+ """
+ Test the osm_cal.py script to ensure it can find the .env file.
+ """
+ print("\n=== Testing osm_cal.py script ===")
+
+ # Backup the .env file if it exists
+ env_exists = os.path.exists('.env')
+ if env_exists:
+ print("Backing up existing .env file...")
+ shutil.copy('.env', '.env.backup')
+
+ # Create a test .env file with minimal required variables
+ print("Creating test .env file at project root...")
+ with open('.env', 'w') as f:
+ f.write("DB_NAME=test_db\n")
+ f.write("DB_HOST=localhost\n")
+ f.write("DB_USER=test_user\n")
+ f.write("POSTGRES_PASSWORD=test_password\n")
+
+ # Test the osm_cal.py script
+ print("Testing osm_cal.py script...")
+ try:
+ # We'll use a very short timeout since we expect it to try to connect to the database
+ # and fail, but we just want to verify it gets past the .env check
+ result = subprocess.run(
+ [sys.executable, 'extractors/osm_cal.py'],
+ capture_output=True,
+ text=True,
+ timeout=2 # Short timeout
+ )
+ print(f"Exit code: {result.returncode}")
+ print(f"Output: {result.stdout}")
+ print(f"Error: {result.stderr}")
+ except subprocess.TimeoutExpired:
+ print("Process timed out - this is expected as it's trying to connect to the database")
+
+ # Clean up
+ os.remove('.env')
+
+ # Restore the original .env file if it existed
+ if env_exists:
+ print("Restoring original .env file...")
+ shutil.move('.env.backup', '.env')
+
+if __name__ == "__main__":
+ test_load_env_from_file_in_root()
+ test_load_env_from_file_in_subdir()
+ test_osm_cal_script()
\ No newline at end of file
diff --git a/test_osm_cal.py b/test_osm_cal.py
new file mode 100755
index 0000000..c82631f
--- /dev/null
+++ b/test_osm_cal.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python3
+"""
+Test script to verify that the osm_cal.py script can successfully submit events to the database.
+"""
+
+import os
+import sys
+import json
+from datetime import datetime, timedelta
+
+# Add the parent directory to the path so we can import from oedb
+sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
+
+from extractors.osm_cal import submit_event, load_env_from_file
+from oedb.utils.logging import logger
+
+def create_test_event():
+ """
+ Create a test event with a simple point geometry.
+ """
+ # Create a point geometry (Paris coordinates)
+ geometry = {
+ "type": "Point",
+ "coordinates": [2.3522, 48.8566]
+ }
+
+ # Create event properties
+ now = datetime.now()
+ tomorrow = now + timedelta(days=1)
+
+ properties = {
+ "type": "scheduled",
+ "what": "test.event",
+ "where": "Paris, France",
+ "label": "Test Event",
+ "description": "This is a test event created by the test_osm_cal.py script",
+ "start": now.isoformat(),
+ "stop": tomorrow.isoformat(),
+ "url": "https://example.com",
+ "external_id": f"test-event-{now.timestamp()}",
+ "source": "Test Script"
+ }
+
+ # Create the event object
+ event = {
+ "type": "Feature",
+ "geometry": geometry,
+ "properties": properties
+ }
+
+ return event
+
+def test_submit_event():
+ """
+ Test the submit_event function with a test event.
+ """
+ logger.info("Starting test_submit_event")
+
+ # Load environment variables from .env file
+ if not load_env_from_file():
+ logger.error("Required .env file not found. Exiting.")
+ sys.exit(1)
+
+ # Create a test event
+ event = create_test_event()
+ logger.info(f"Created test event: {event['properties']['label']}")
+
+ # Submit the event
+ logger.info("Submitting test event to the database...")
+ result = submit_event(event)
+
+ if result:
+ logger.success("Successfully submitted test event to the database")
+ else:
+ logger.error("Failed to submit test event to the database")
+
+ return result
+
+if __name__ == "__main__":
+ test_submit_event()
\ No newline at end of file