467 lines
No EOL
18 KiB
Python
467 lines
No EOL
18 KiB
Python
"""
|
|
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 = """
|
|
<!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])
|
|
|
|
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>'
|
|
|
|
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)}"
|
|
|
|
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() |