| 
									
										
										
										
											2025-09-16 00:04:53 +02:00
										 |  |  | """
 | 
					
						
							|  |  |  | Demo resource for the OpenEventDatabase. | 
					
						
							| 
									
										
										
										
											2025-09-21 13:35:01 +02:00
										 |  |  | This module imports and re-exports the demo resources from the demo package. | 
					
						
							| 
									
										
										
										
											2025-09-16 00:04:53 +02:00
										 |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import falcon | 
					
						
							| 
									
										
										
										
											2025-09-16 01:01:32 +02:00
										 |  |  | import requests | 
					
						
							|  |  |  | import json | 
					
						
							| 
									
										
										
										
											2025-09-21 12:27:00 +02:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											2025-09-16 01:01:32 +02:00
										 |  |  | from collections import defaultdict | 
					
						
							| 
									
										
										
										
											2025-09-16 00:04:53 +02:00
										 |  |  | from oedb.utils.logging import logger | 
					
						
							| 
									
										
										
										
											2025-09-21 12:27:00 +02:00
										 |  |  | from oedb.utils.db import load_env_from_file | 
					
						
							| 
									
										
										
										
											2025-09-21 13:35:01 +02:00
										 |  |  | from oedb.resources.demo import demo_main, demo_traffic, demo_view_events | 
					
						
							| 
									
										
										
										
											2025-09-16 00:04:53 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | class DemoResource: | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Resource for the demo endpoint. | 
					
						
							| 
									
										
										
										
											2025-09-16 01:09:20 +02:00
										 |  |  |     Handles the /demo endpoint and related demo pages. | 
					
						
							| 
									
										
										
										
											2025-09-16 00:04:53 +02:00
										 |  |  |     """
 | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2025-09-26 14:18:14 +02:00
										 |  |  |     def __init__(self): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Initialize the resource with a Jinja2 environment. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         # Set up Jinja2 environment | 
					
						
							|  |  |  |         import jinja2 | 
					
						
							|  |  |  |         import os | 
					
						
							|  |  |  |         template_dir = os.path.join(os.path.dirname(__file__), 'demo', 'templates') | 
					
						
							|  |  |  |         self.jinja_env = jinja2.Environment( | 
					
						
							|  |  |  |             loader=jinja2.FileSystemLoader(template_dir), | 
					
						
							|  |  |  |             autoescape=jinja2.select_autoescape(['html', 'xml']) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2025-09-16 01:09:20 +02:00
										 |  |  |     def on_get_edit(self, req, resp, id=None): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Handle GET requests to the /demo/edit endpoint. | 
					
						
							|  |  |  |         Returns an HTML page with a form for editing an existing event. | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         Args: | 
					
						
							|  |  |  |             req: The request object. | 
					
						
							|  |  |  |             resp: The response object. | 
					
						
							|  |  |  |             id: The event ID to edit. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         logger.info(f"Processing GET request to /demo/edit for event ID: {id}") | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         if id is None: | 
					
						
							|  |  |  |             resp.status = falcon.HTTP_400 | 
					
						
							|  |  |  |             resp.text = "Event ID is required" | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             # Set content type to HTML | 
					
						
							|  |  |  |             resp.content_type = 'text/html' | 
					
						
							|  |  |  |              | 
					
						
							| 
									
										
										
										
											2025-09-27 01:31:36 +02:00
										 |  |  |             # Fetch the event data from the OEDB API | 
					
						
							|  |  |  |             logger.info(f"Fetching event data from API for event ID: {id}") | 
					
						
							| 
									
										
										
										
											2025-09-21 23:59:01 +02:00
										 |  |  |             response = requests.get(f'https://api.openeventdatabase.org/event/{id}') | 
					
						
							| 
									
										
										
										
											2025-09-27 01:31:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-16 01:09:20 +02:00
										 |  |  |             if response.status_code != 200: | 
					
						
							| 
									
										
										
										
											2025-09-27 01:31:36 +02:00
										 |  |  |                 logger.error(f"API returned status {response.status_code} for event {id}") | 
					
						
							| 
									
										
										
										
											2025-09-16 01:09:20 +02:00
										 |  |  |                 resp.status = falcon.HTTP_404 | 
					
						
							| 
									
										
										
										
											2025-09-27 01:31:36 +02:00
										 |  |  |                 resp.text = f"Event with ID {id} not found on API" | 
					
						
							| 
									
										
										
										
											2025-09-16 01:09:20 +02:00
										 |  |  |                 return | 
					
						
							| 
									
										
										
										
											2025-09-27 01:31:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-16 01:09:20 +02:00
										 |  |  |             event_data = response.json() | 
					
						
							| 
									
										
										
										
											2025-09-27 01:31:36 +02:00
										 |  |  |             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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-26 15:08:33 +02:00
										 |  |  |             # Render the template with the event data | 
					
						
							|  |  |  |             template = self.jinja_env.get_template('edit.html') | 
					
						
							|  |  |  |             html = template.render( | 
					
						
							|  |  |  |                 id=id, | 
					
						
							| 
									
										
										
										
											2025-09-27 01:31:36 +02:00
										 |  |  |                 event_data=event_data  # Pass Python object directly, let Jinja2 handle JSON conversion | 
					
						
							| 
									
										
										
										
											2025-09-26 15:08:33 +02:00
										 |  |  |             ) | 
					
						
							| 
									
										
										
										
											2025-09-27 01:31:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-16 01:09:20 +02:00
										 |  |  |             # Set the response body and status | 
					
						
							| 
									
										
										
										
											2025-09-26 15:08:33 +02:00
										 |  |  |             resp.text = html | 
					
						
							| 
									
										
										
										
											2025-09-16 01:09:20 +02:00
										 |  |  |             resp.status = falcon.HTTP_200 | 
					
						
							|  |  |  |             logger.success(f"Successfully processed GET request to /demo/edit for event ID: {id}") | 
					
						
							| 
									
										
										
										
											2025-09-27 01:31:36 +02:00
										 |  |  |         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)}" | 
					
						
							| 
									
										
										
										
											2025-09-16 01:09:20 +02:00
										 |  |  |         except Exception as e: | 
					
						
							|  |  |  |             logger.error(f"Error processing GET request to /demo/edit: {e}") | 
					
						
							|  |  |  |             resp.status = falcon.HTTP_500 | 
					
						
							|  |  |  |             resp.text = f"Error: {str(e)}" | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2025-09-16 00:04:53 +02:00
										 |  |  |     def on_get(self, req, resp): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Handle GET requests to the /demo endpoint. | 
					
						
							| 
									
										
										
										
											2025-09-21 13:35:01 +02:00
										 |  |  |         Delegates to the demo_main resource. | 
					
						
							| 
									
										
										
										
											2025-09-16 00:04:53 +02:00
										 |  |  |          | 
					
						
							|  |  |  |         Args: | 
					
						
							|  |  |  |             req: The request object. | 
					
						
							|  |  |  |             resp: The response object. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2025-09-21 13:35:01 +02:00
										 |  |  |         return demo_main.on_get(req, resp) | 
					
						
							| 
									
										
										
										
											2025-09-16 01:01:32 +02:00
										 |  |  |      | 
					
						
							|  |  |  |     def on_get_by_what(self, req, resp): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Handle GET requests to the /demo/by-what endpoint. | 
					
						
							|  |  |  |         Returns an HTML page with links to events organized by their "what" type. | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         Args: | 
					
						
							|  |  |  |             req: The request object. | 
					
						
							|  |  |  |             resp: The response object. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         logger.info("Processing GET request to /demo/by-what") | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             # Set content type to HTML | 
					
						
							|  |  |  |             resp.content_type = 'text/html' | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             # Fetch events from the API | 
					
						
							| 
									
										
										
										
											2025-09-18 19:27:28 +02:00
										 |  |  |             try: | 
					
						
							| 
									
										
										
										
											2025-10-10 17:56:50 +02:00
										 |  |  |                 response = requests.get('/event?limit=5000') | 
					
						
							| 
									
										
										
										
											2025-09-18 19:27:28 +02:00
										 |  |  |                 if response.status_code == 200 and response.text: | 
					
						
							|  |  |  |                     events_data = response.json() | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     logger.error(f"Error fetching events: Status code {response.status_code}, Response: {response.text}") | 
					
						
							|  |  |  |                     events_data = {"features": []} | 
					
						
							|  |  |  |             except json.JSONDecodeError as e: | 
					
						
							|  |  |  |                 logger.error(f"Error parsing JSON response: {e}") | 
					
						
							|  |  |  |                 events_data = {"features": []} | 
					
						
							|  |  |  |             except Exception as e: | 
					
						
							|  |  |  |                 logger.error(f"Error fetching events: {e}") | 
					
						
							|  |  |  |                 events_data = {"features": []} | 
					
						
							| 
									
										
										
										
											2025-09-16 01:01:32 +02:00
										 |  |  |              | 
					
						
							|  |  |  |             # Group events by "what" type | 
					
						
							|  |  |  |             events_by_what = defaultdict(list) | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             if events_data.get('features'): | 
					
						
							|  |  |  |                 for feature in events_data['features']: | 
					
						
							|  |  |  |                     properties = feature.get('properties', {}) | 
					
						
							|  |  |  |                     what = properties.get('what', 'Unknown') | 
					
						
							|  |  |  |                     events_by_what[what].append({ | 
					
						
							|  |  |  |                         'id': properties.get('id'), | 
					
						
							|  |  |  |                         'label': properties.get('label', 'Unnamed Event'), | 
					
						
							|  |  |  |                         'coordinates': feature.get('geometry', {}).get('coordinates', [0, 0]) | 
					
						
							|  |  |  |                     }) | 
					
						
							|  |  |  |              | 
					
						
							| 
									
										
										
										
											2025-09-26 15:08:33 +02:00
										 |  |  |             # Load and render the template with the appropriate variables | 
					
						
							|  |  |  |             template = self.jinja_env.get_template('by_what.html') | 
					
						
							| 
									
										
										
										
											2025-09-16 01:01:32 +02:00
										 |  |  |              | 
					
						
							| 
									
										
										
										
											2025-09-26 15:08:33 +02:00
										 |  |  |             # Sort event types alphabetically if we have events | 
					
						
							|  |  |  |             sorted_what_types = sorted(events_by_what.keys()) if events_by_what else [] | 
					
						
							| 
									
										
										
										
											2025-09-16 01:01:32 +02:00
										 |  |  |              | 
					
						
							| 
									
										
										
										
											2025-09-26 15:08:33 +02:00
										 |  |  |             html = template.render( | 
					
						
							|  |  |  |                 events_by_what=events_by_what, | 
					
						
							|  |  |  |                 sorted_what_types=sorted_what_types | 
					
						
							|  |  |  |             ) | 
					
						
							| 
									
										
										
										
											2025-09-16 01:01:32 +02:00
										 |  |  |              | 
					
						
							|  |  |  |             # Set the response body and status | 
					
						
							|  |  |  |             resp.text = html | 
					
						
							|  |  |  |             resp.status = falcon.HTTP_200 | 
					
						
							|  |  |  |             logger.success("Successfully processed GET request to /demo/by-what") | 
					
						
							|  |  |  |         except Exception as e: | 
					
						
							|  |  |  |             logger.error(f"Error processing GET request to /demo/by-what: {e}") | 
					
						
							|  |  |  |             resp.status = falcon.HTTP_500 | 
					
						
							|  |  |  |             resp.text = f"Error: {str(e)}" | 
					
						
							|  |  |  |          | 
					
						
							| 
									
										
										
										
											2025-09-18 23:43:06 +02:00
										 |  |  |     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' | 
					
						
							|  |  |  |              | 
					
						
							| 
									
										
										
										
											2025-09-26 15:08:33 +02:00
										 |  |  |             # Render the template | 
					
						
							|  |  |  |             template = self.jinja_env.get_template('search.html') | 
					
						
							|  |  |  |             html = template.render() | 
					
						
							| 
									
										
										
										
											2025-09-18 23:43:06 +02:00
										 |  |  |              | 
					
						
							|  |  |  |             # 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)}" | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2025-09-16 01:01:32 +02:00
										 |  |  |     def on_get_map_by_what(self, req, resp): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Handle GET requests to the /demo/map-by-what endpoint. | 
					
						
							|  |  |  |         Returns an HTML page with a MapLibre map showing events filtered by "what" type. | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         Args: | 
					
						
							|  |  |  |             req: The request object. | 
					
						
							|  |  |  |             resp: The response object. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         logger.info("Processing GET request to /demo/map-by-what") | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             # Set content type to HTML | 
					
						
							|  |  |  |             resp.content_type = 'text/html' | 
					
						
							|  |  |  |              | 
					
						
							| 
									
										
										
										
											2025-09-26 15:08:33 +02:00
										 |  |  |             # Render the template | 
					
						
							|  |  |  |             template = self.jinja_env.get_template('map_by_what.html') | 
					
						
							|  |  |  |             html = template.render() | 
					
						
							| 
									
										
										
										
											2025-09-16 01:01:32 +02:00
										 |  |  |              | 
					
						
							|  |  |  |             # Set the response body and status | 
					
						
							|  |  |  |             resp.text = html | 
					
						
							|  |  |  |             resp.status = falcon.HTTP_200 | 
					
						
							|  |  |  |             logger.success("Successfully processed GET request to /demo/map-by-what") | 
					
						
							|  |  |  |         except Exception as e: | 
					
						
							|  |  |  |             logger.error(f"Error processing GET request to /demo/map-by-what: {e}") | 
					
						
							|  |  |  |             resp.status = falcon.HTTP_500 | 
					
						
							|  |  |  |             resp.text = f"Error: {str(e)}" | 
					
						
							| 
									
										
										
										
											2025-09-26 17:38:30 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def on_get_map_by_what_type(self, req, resp, event_type): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Handle GET requests to the /demo/map-by-what/{type} endpoint. | 
					
						
							|  |  |  |         Returns an HTML page with a MapLibre map showing events of a specific type, | 
					
						
							|  |  |  |         colored by temporality (past/present/future) with a detailed table. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Args: | 
					
						
							|  |  |  |             req: The request object. | 
					
						
							|  |  |  |             resp: The response object. | 
					
						
							|  |  |  |             event_type: The event type to filter by. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         logger.info(f"Processing GET request to /demo/map-by-what/{event_type}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             # Set content type to HTML | 
					
						
							|  |  |  |             resp.content_type = 'text/html' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Render the template with the event type | 
					
						
							|  |  |  |             template = self.jinja_env.get_template('map_by_what_type.html') | 
					
						
							|  |  |  |             html = template.render( | 
					
						
							|  |  |  |                 event_type=event_type, | 
					
						
							|  |  |  |                 event_type_label=event_type.replace('_', ' ').title() | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Set the response body and status | 
					
						
							|  |  |  |             resp.text = html | 
					
						
							|  |  |  |             resp.status = falcon.HTTP_200 | 
					
						
							|  |  |  |             logger.success(f"Successfully processed GET request to /demo/map-by-what/{event_type}") | 
					
						
							|  |  |  |         except Exception as e: | 
					
						
							|  |  |  |             logger.error(f"Error processing GET request to /demo/map-by-what/{event_type}: {e}") | 
					
						
							|  |  |  |             resp.status = falcon.HTTP_500 | 
					
						
							|  |  |  |             resp.text = f"Error: {str(e)}" | 
					
						
							| 
									
										
										
										
											2025-09-16 01:01:32 +02:00
										 |  |  |             events_by_what = defaultdict(list) | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             if events_data.get('features'): | 
					
						
							|  |  |  |                 for feature in events_data['features']: | 
					
						
							|  |  |  |                     properties = feature.get('properties', {}) | 
					
						
							|  |  |  |                     what = properties.get('what', 'Unknown') | 
					
						
							|  |  |  |                     events_by_what[what].append({ | 
					
						
							|  |  |  |                         'id': properties.get('id'), | 
					
						
							|  |  |  |                         'label': properties.get('label', 'Unnamed Event'), | 
					
						
							|  |  |  |                         'coordinates': feature.get('geometry', {}).get('coordinates', [0, 0]) | 
					
						
							|  |  |  |                     }) | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             # Create HTML response | 
					
						
							|  |  |  |             html = """
 | 
					
						
							|  |  |  |             <!DOCTYPE html> | 
					
						
							|  |  |  |             <html lang="en"> | 
					
						
							|  |  |  |             <head> | 
					
						
							|  |  |  |                 <meta charset="UTF-8"> | 
					
						
							|  |  |  |                 <meta name="viewport" content="width=device-width, initial-scale=1.0"> | 
					
						
							|  |  |  |                 <title>Events by Type - OpenEventDatabase</title> | 
					
						
							|  |  |  |                 <style> | 
					
						
							|  |  |  |                     body {  | 
					
						
							|  |  |  |                         font-family: Arial, sans-serif;  | 
					
						
							|  |  |  |                         line-height: 1.6; | 
					
						
							|  |  |  |                         max-width: 1200px; | 
					
						
							|  |  |  |                         margin: 0 auto; | 
					
						
							|  |  |  |                         padding: 20px; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     h1 { color: #333; } | 
					
						
							|  |  |  |                     h2 {  | 
					
						
							|  |  |  |                         color: #0078ff;  | 
					
						
							|  |  |  |                         margin-top: 30px; | 
					
						
							|  |  |  |                         padding-bottom: 5px; | 
					
						
							|  |  |  |                         border-bottom: 1px solid #eee; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     ul { padding-left: 20px; } | 
					
						
							|  |  |  |                     li { margin-bottom: 8px; } | 
					
						
							|  |  |  |                     a { color: #0078ff; text-decoration: none; } | 
					
						
							|  |  |  |                     a:hover { text-decoration: underline; } | 
					
						
							|  |  |  |                     .nav {  | 
					
						
							|  |  |  |                         background-color: #f5f5f5; | 
					
						
							|  |  |  |                         padding: 10px; | 
					
						
							|  |  |  |                         border-radius: 5px; | 
					
						
							|  |  |  |                         margin-bottom: 20px; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     .nav a { | 
					
						
							|  |  |  |                         margin-right: 15px; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     .event-count { | 
					
						
							|  |  |  |                         color: #666; | 
					
						
							|  |  |  |                         font-size: 0.9em; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 </style> | 
					
						
							|  |  |  |             </head> | 
					
						
							|  |  |  |             <body> | 
					
						
							|  |  |  |                 <div class="nav"> | 
					
						
							|  |  |  |                     <a href="/">Home</a> | 
					
						
							|  |  |  |                     <a href="/demo">Demo Map</a> | 
					
						
							|  |  |  |                     <a href="/demo/map-by-what">Map by Event Type</a> | 
					
						
							|  |  |  |                 </div> | 
					
						
							|  |  |  |                  | 
					
						
							|  |  |  |                 <h1>Events by Type</h1> | 
					
						
							|  |  |  |                 <p>This page lists all events from the OpenEventDatabase organized by their type.</p> | 
					
						
							|  |  |  |             """
 | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             # Add event types and their events | 
					
						
							|  |  |  |             if events_by_what: | 
					
						
							|  |  |  |                 # Sort event types alphabetically | 
					
						
							|  |  |  |                 sorted_what_types = sorted(events_by_what.keys()) | 
					
						
							|  |  |  |                  | 
					
						
							|  |  |  |                 # Add quick navigation | 
					
						
							|  |  |  |                 html += "<h2>Quick Navigation</h2><ul>" | 
					
						
							|  |  |  |                 for what_type in sorted_what_types: | 
					
						
							|  |  |  |                     event_count = len(events_by_what[what_type]) | 
					
						
							|  |  |  |                     html += f'<li><a href="#what-{what_type.replace(" ", "-")}">{what_type}</a> <span class="event-count">({event_count} events)</span></li>' | 
					
						
							|  |  |  |                 html += "</ul>" | 
					
						
							|  |  |  |                  | 
					
						
							|  |  |  |                 # Add sections for each event type | 
					
						
							|  |  |  |                 for what_type in sorted_what_types: | 
					
						
							|  |  |  |                     events = events_by_what[what_type] | 
					
						
							|  |  |  |                     html += f'<h2 id="what-{what_type.replace(" ", "-")}">{what_type} <span class="event-count">({len(events)} events)</span></h2>' | 
					
						
							|  |  |  |                     html += "<ul>" | 
					
						
							|  |  |  |                      | 
					
						
							|  |  |  |                     # Sort events by label | 
					
						
							|  |  |  |                     sorted_events = sorted(events, key=lambda x: x.get('label', '')) | 
					
						
							|  |  |  |                      | 
					
						
							|  |  |  |                     for event in sorted_events: | 
					
						
							|  |  |  |                         event_id = event.get('id') | 
					
						
							|  |  |  |                         event_label = event.get('label', 'Unnamed Event') | 
					
						
							|  |  |  |                         coordinates = event.get('coordinates', [0, 0]) | 
					
						
							|  |  |  |                          | 
					
						
							| 
									
										
										
										
											2025-09-21 17:30:47 +02:00
										 |  |  |                         html += f'<li><a href="/event/{event_id}" >{event_label}</a> ' | 
					
						
							|  |  |  |                         html += f'<small>[<a href="https://www.openstreetmap.org/?mlat={coordinates[1]}&mlon={coordinates[0]}&zoom=15" >map</a>]</small></li>' | 
					
						
							| 
									
										
										
										
											2025-09-16 01:01:32 +02:00
										 |  |  |                      | 
					
						
							|  |  |  |                     html += "</ul>" | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 html += "<p>No events found in the database.</p>" | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             html += """
 | 
					
						
							|  |  |  |             </body> | 
					
						
							|  |  |  |             </html> | 
					
						
							|  |  |  |             """
 | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             # Set the response body and status | 
					
						
							|  |  |  |             resp.text = html | 
					
						
							|  |  |  |             resp.status = falcon.HTTP_200 | 
					
						
							|  |  |  |             logger.success("Successfully processed GET request to /demo/by-what") | 
					
						
							|  |  |  |         except Exception as e: | 
					
						
							|  |  |  |             logger.error(f"Error processing GET request to /demo/by-what: {e}") | 
					
						
							|  |  |  |             resp.status = falcon.HTTP_500 | 
					
						
							|  |  |  |             resp.text = f"Error: {str(e)}" | 
					
						
							| 
									
										
										
										
											2025-09-16 00:04:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-21 12:27:00 +02:00
										 |  |  |     def on_get_traffic(self, req, resp): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Handle GET requests to the /demo/traffic endpoint. | 
					
						
							| 
									
										
										
										
											2025-09-21 13:35:01 +02:00
										 |  |  |         Delegates to the demo_traffic resource. | 
					
						
							| 
									
										
										
										
											2025-09-21 12:27:00 +02:00
										 |  |  |          | 
					
						
							|  |  |  |         Args: | 
					
						
							|  |  |  |             req: The request object. | 
					
						
							|  |  |  |             resp: The response object. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2025-09-21 13:35:01 +02:00
										 |  |  |         return demo_traffic.on_get(req, resp) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def on_get_view_events(self, req, resp): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Handle GET requests to the /demo/view-events endpoint. | 
					
						
							|  |  |  |         Delegates to the demo_view_events resource. | 
					
						
							| 
									
										
										
										
											2025-09-21 17:30:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-21 13:35:01 +02:00
										 |  |  |         Args: | 
					
						
							|  |  |  |             req: The request object. | 
					
						
							|  |  |  |             resp: The response object. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         return demo_view_events.on_get(req, resp) | 
					
						
							| 
									
										
										
										
											2025-09-21 12:27:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-26 11:57:54 +02:00
										 |  |  |     def on_get_by_id(self, req, resp, id): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Handle GET requests to /demo/by_id/{id}. | 
					
						
							|  |  |  |         Show a map with the event location and a table of its properties. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         import requests | 
					
						
							| 
									
										
										
										
											2025-09-26 14:18:14 +02:00
										 |  |  |         import json | 
					
						
							| 
									
										
										
										
											2025-09-26 11:57:54 +02:00
										 |  |  |         logger.info(f"Processing GET request to /demo/by_id/{id}") | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             resp.content_type = 'text/html' | 
					
						
							|  |  |  |             r = requests.get(f"https://api.openeventdatabase.org/event/{id}") | 
					
						
							|  |  |  |             r.raise_for_status() | 
					
						
							|  |  |  |             feature = r.json() | 
					
						
							| 
									
										
										
										
											2025-09-26 14:18:14 +02:00
										 |  |  |              | 
					
						
							|  |  |  |             # Load and render the template | 
					
						
							|  |  |  |             template = self.jinja_env.get_template('event_details.html') | 
					
						
							|  |  |  |             html = template.render( | 
					
						
							|  |  |  |                 id=id, | 
					
						
							|  |  |  |                 feature_json=json.dumps(feature), | 
					
						
							|  |  |  |                 properties=feature.get('properties') or {} | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |              | 
					
						
							| 
									
										
										
										
											2025-09-26 11:57:54 +02:00
										 |  |  |             resp.text = html | 
					
						
							|  |  |  |             resp.status = falcon.HTTP_200 | 
					
						
							|  |  |  |             logger.success(f"Successfully processed GET request to /demo/by_id/{id}") | 
					
						
							|  |  |  |         except Exception as e: | 
					
						
							|  |  |  |             logger.error(f"Error processing GET request to /demo/by_id/{id}: {e}") | 
					
						
							|  |  |  |             resp.status = falcon.HTTP_500 | 
					
						
							|  |  |  |             resp.text = f"Error: {str(e)}" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-27 00:39:18 +02:00
										 |  |  |     def on_get_property_stats(self, req, resp): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         Handle GET requests to the /demo/property-stats endpoint. | 
					
						
							|  |  |  |         Returns an HTML page with statistics about property occurrences in the last 200 events. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Args: | 
					
						
							|  |  |  |             req: The request object. | 
					
						
							|  |  |  |             resp: The response object. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         logger.info("Processing GET request to /demo/property-stats") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             # Set content type to HTML | 
					
						
							|  |  |  |             resp.content_type = 'text/html' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Fetch the last 200 events from the API | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 response = requests.get('https://api.openeventdatabase.org/event?limit=200') | 
					
						
							|  |  |  |                 if response.status_code == 200 and response.text: | 
					
						
							|  |  |  |                     events_data = response.json() | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     logger.error(f"Error fetching events: Status code {response.status_code}") | 
					
						
							|  |  |  |                     events_data = {"features": []} | 
					
						
							|  |  |  |             except Exception as e: | 
					
						
							|  |  |  |                 logger.error(f"Error fetching events: {e}") | 
					
						
							|  |  |  |                 events_data = {"features": []} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Count property occurrences | 
					
						
							|  |  |  |             property_counts = {} | 
					
						
							|  |  |  |             total_events = len(events_data.get('features', [])) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for feature in events_data.get('features', []): | 
					
						
							|  |  |  |                 properties = feature.get('properties', {}) | 
					
						
							|  |  |  |                 for prop_name in properties.keys(): | 
					
						
							|  |  |  |                     if prop_name in property_counts: | 
					
						
							|  |  |  |                         property_counts[prop_name] += 1 | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         property_counts[prop_name] = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Sort properties by occurrence count (descending order) | 
					
						
							|  |  |  |             sorted_properties = sorted(property_counts.items(), key=lambda x: x[1], reverse=True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Render the template | 
					
						
							|  |  |  |             template = self.jinja_env.get_template('property_stats.html') | 
					
						
							|  |  |  |             html = template.render( | 
					
						
							|  |  |  |                 property_stats=sorted_properties, | 
					
						
							|  |  |  |                 total_events=total_events, | 
					
						
							|  |  |  |                 unique_properties=len(sorted_properties) | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Set the response body and status | 
					
						
							|  |  |  |             resp.text = html | 
					
						
							|  |  |  |             resp.status = falcon.HTTP_200 | 
					
						
							|  |  |  |             logger.success("Successfully processed GET request to /demo/property-stats") | 
					
						
							|  |  |  |         except Exception as e: | 
					
						
							|  |  |  |             logger.error(f"Error processing GET request to /demo/property-stats: {e}") | 
					
						
							|  |  |  |             resp.status = falcon.HTTP_500 | 
					
						
							|  |  |  |             resp.text = f"Error: {str(e)}" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-16 00:04:53 +02:00
										 |  |  | # Create a global instance of DemoResource | 
					
						
							|  |  |  | demo = DemoResource() |