""" Demo resource for the OpenEventDatabase. This module imports and re-exports the demo resources from the demo package. """ import falcon import requests import json import os from collections import defaultdict from oedb.utils.logging import logger from oedb.utils.db import load_env_from_file from oedb.resources.demo import demo_main, demo_traffic, demo_view_events class DemoResource: """ Resource for the demo endpoint. Handles the /demo endpoint and related demo pages. """ 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']) ) 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' # Fetch the event data from the API response = requests.get(f'https://api.openeventdatabase.org/event/{id}') if response.status_code != 200: resp.status = falcon.HTTP_404 resp.text = f"Event with ID {id} not found" return event_data = response.json() # Render the template with the event data template = self.jinja_env.get_template('edit.html') html = template.render( id=id, event_data=event_data ) # Set the response body and status resp.text = html resp.status = falcon.HTTP_200 logger.success(f"Successfully processed GET request to /demo/edit for event ID: {id}") 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)}" def on_get(self, req, resp): """ Handle GET requests to the /demo endpoint. Delegates to the demo_main resource. Args: req: The request object. resp: The response object. """ return demo_main.on_get(req, resp) 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 try: response = requests.get('/event?limit=1000') 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": []} # 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]) }) # Load and render the template with the appropriate variables template = self.jinja_env.get_template('by_what.html') # Sort event types alphabetically if we have events sorted_what_types = sorted(events_by_what.keys()) if events_by_what else [] html = template.render( events_by_what=events_by_what, sorted_what_types=sorted_what_types ) # 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)}" 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' # Render the template template = self.jinja_env.get_template('search.html') html = template.render() # 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. 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' # Render the template template = self.jinja_env.get_template('map_by_what.html') html = template.render() # 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)}" 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)}" 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 = """
This page lists all events from the OpenEventDatabase organized by their type.
""" # 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 += "No events found in the database.
" 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)}" def on_get_traffic(self, req, resp): """ Handle GET requests to the /demo/traffic endpoint. Delegates to the demo_traffic resource. Args: req: The request object. resp: The response object. """ 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. Args: req: The request object. resp: The response object. """ return demo_view_events.on_get(req, resp) 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 import json 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() # 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 {} ) 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)}" 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)}" # Create a global instance of DemoResource demo = DemoResource()