add center and radius params
This commit is contained in:
75
README.md
75
README.md
@@ -401,6 +401,81 @@ curl "http://localhost:7000/plexts?min_timestamp=2026-01-12T10:00:00Z&max_timest
|
|||||||
curl "http://localhost:7000/plexts?event_types=PORTAL_CAPTURED&player_name=Albicocca&min_timestamp=2026-01-12T10:00:00Z"
|
curl "http://localhost:7000/plexts?event_types=PORTAL_CAPTURED&player_name=Albicocca&min_timestamp=2026-01-12T10:00:00Z"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
##### GET /plexts/from-db
|
||||||
|
|
||||||
|
Get plexts from MongoDB with optional filters. Returns plexts sorted by timestamp (most recent first).
|
||||||
|
|
||||||
|
**Query Parameters:**
|
||||||
|
|
||||||
|
| Parameter | Type | Default | Description |
|
||||||
|
| --------------- | ------- | -------- | --------------------------------------------------- |
|
||||||
|
| `player_name` | String | None | Player name to filter by |
|
||||||
|
| `timestamp_from` | Integer | None | Minimum timestamp in milliseconds (optional) |
|
||||||
|
| `timestamp_to` | Integer | None | Maximum timestamp in milliseconds (optional) |
|
||||||
|
| `limit` | Integer | 100 | Maximum number of results to return |
|
||||||
|
| `center` | String | None | Geographic center point in format "latitude,longitude" (optional, requires radius) |
|
||||||
|
| `radius` | Integer | None | Search radius in meters (optional, requires center) |
|
||||||
|
|
||||||
|
**Geospatial Query:**
|
||||||
|
|
||||||
|
When both `center` and `radius` parameters are provided, the endpoint returns plexts within the specified radius from the center point. The response includes a `distance` field (in meters) for each result.
|
||||||
|
|
||||||
|
**Response with geospatial query:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"count": 5,
|
||||||
|
"plexts": [
|
||||||
|
{
|
||||||
|
"id": "abc123",
|
||||||
|
"timestamp": 1736659207000,
|
||||||
|
"timestamp_formatted": "2026-01-12 11:00:07",
|
||||||
|
"text": "Albicocca captured L' Arboreto",
|
||||||
|
"team": "RESISTANCE",
|
||||||
|
"plext_type": "PLAYER_GENERATED",
|
||||||
|
"categories": 0,
|
||||||
|
"event_type": "PORTAL_CAPTURED",
|
||||||
|
"player_name": "Albicocca",
|
||||||
|
"portal_name": "L' Arboreto",
|
||||||
|
"coordinates": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [12.365208, 45.573661]
|
||||||
|
},
|
||||||
|
"distance": 125.5,
|
||||||
|
"markup": [...]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** Both `center` and `radius` parameters must be provided together. If neither is provided, the endpoint returns all plexts matching other filters without geospatial filtering.
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Get all plexts from MongoDB
|
||||||
|
curl "http://localhost:7000/plexts/from-db"
|
||||||
|
|
||||||
|
# Filter by player name
|
||||||
|
curl "http://localhost:7000/plexts/from-db?player_name=Albicocca"
|
||||||
|
|
||||||
|
# Filter by time range
|
||||||
|
curl "http://localhost:7000/plexts/from-db?timestamp_from=17366592000000×tamp_to=1736745600000"
|
||||||
|
|
||||||
|
# Geospatial query: Get plexts within 1km of a specific location
|
||||||
|
curl "http://localhost:7000/plexts/from-db?center=45.573661,12.365208&radius=1000"
|
||||||
|
|
||||||
|
# Geospatial query with player filter
|
||||||
|
curl "http://localhost:7000/plexts/from-db?center=45.573661,12.365208&radius=1000&player_name=Albicocca"
|
||||||
|
|
||||||
|
# Geospatial query with time filter
|
||||||
|
curl "http://localhost:7000/plexts/from-db?center=45.573661,12.365208&radius=1000×tamp_from=17366592000000"
|
||||||
|
|
||||||
|
# Combine all filters
|
||||||
|
curl "http://localhost:7000/plexts/from-db?center=45.573661,12.365208&radius=1000&player_name=Albicocca×tamp_from=17366592000000&limit=10"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Authentication:** Basic Auth required
|
||||||
|
|
||||||
### Scheduler
|
### Scheduler
|
||||||
|
|
||||||
The scheduler automatically collects Ingress events every minute and stores them in MongoDB.
|
The scheduler automatically collects Ingress events every minute and stores them in MongoDB.
|
||||||
|
|||||||
113
app.py
113
app.py
@@ -32,9 +32,12 @@ def get_plexts_from_db():
|
|||||||
timestamp_from: Minimum timestamp in milliseconds (optional)
|
timestamp_from: Minimum timestamp in milliseconds (optional)
|
||||||
timestamp_to: Maximum timestamp in milliseconds (optional)
|
timestamp_to: Maximum timestamp in milliseconds (optional)
|
||||||
limit: Maximum number of results to return (optional, default: 100)
|
limit: Maximum number of results to return (optional, default: 100)
|
||||||
|
center: Geographic center point in format "latitude,longitude" (optional, requires radius)
|
||||||
|
radius: Search radius in meters (optional, requires center)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
JSON response with list of plexts (without _id field), limited by the limit parameter
|
JSON response with list of plexts (without _id field), limited by the limit parameter.
|
||||||
|
When using geospatial query (center and radius), includes a 'distance' field in meters.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Parse query parameters
|
# Parse query parameters
|
||||||
@@ -42,6 +45,8 @@ def get_plexts_from_db():
|
|||||||
timestamp_from = request.args.get("timestamp_from")
|
timestamp_from = request.args.get("timestamp_from")
|
||||||
timestamp_to = request.args.get("timestamp_to")
|
timestamp_to = request.args.get("timestamp_to")
|
||||||
limit_param = request.args.get("limit")
|
limit_param = request.args.get("limit")
|
||||||
|
center = request.args.get("center")
|
||||||
|
radius = request.args.get("radius")
|
||||||
|
|
||||||
# Validate and convert timestamp parameters to integers if provided
|
# Validate and convert timestamp parameters to integers if provided
|
||||||
if timestamp_from is not None:
|
if timestamp_from is not None:
|
||||||
@@ -67,6 +72,44 @@ def get_plexts_from_db():
|
|||||||
else:
|
else:
|
||||||
limit = 100
|
limit = 100
|
||||||
|
|
||||||
|
# Validate geospatial parameters
|
||||||
|
# Both center and radius must be provided together, or neither
|
||||||
|
if (center is not None) != (radius is not None):
|
||||||
|
return jsonify({
|
||||||
|
"error": "Both 'center' and 'radius' parameters must be provided together"
|
||||||
|
}), 400
|
||||||
|
|
||||||
|
# Parse and validate center parameter if provided
|
||||||
|
center_coords = None
|
||||||
|
if center is not None:
|
||||||
|
try:
|
||||||
|
# Parse center in format "latitude,longitude"
|
||||||
|
lat_str, lng_str = center.split(',')
|
||||||
|
lat = float(lat_str)
|
||||||
|
lng = float(lng_str)
|
||||||
|
|
||||||
|
# Validate latitude and longitude ranges
|
||||||
|
if not (-90 <= lat <= 90):
|
||||||
|
return jsonify({"error": "Latitude must be between -90 and 90"}), 400
|
||||||
|
if not (-180 <= lng <= 180):
|
||||||
|
return jsonify({"error": "Longitude must be between -180 and 180"}), 400
|
||||||
|
|
||||||
|
center_coords = (lat, lng)
|
||||||
|
except ValueError:
|
||||||
|
return jsonify({
|
||||||
|
"error": "Invalid center format. Use format: 'latitude,longitude' (e.g., '45.573661,12.365208')"
|
||||||
|
}), 400
|
||||||
|
|
||||||
|
# Parse and validate radius parameter if provided
|
||||||
|
radius_meters = None
|
||||||
|
if radius is not None:
|
||||||
|
try:
|
||||||
|
radius_meters = int(radius)
|
||||||
|
if radius_meters <= 0:
|
||||||
|
return jsonify({"error": "Radius must be a positive integer"}), 400
|
||||||
|
except ValueError:
|
||||||
|
return jsonify({"error": "Radius must be an integer"}), 400
|
||||||
|
|
||||||
# Build MongoDB filter query
|
# Build MongoDB filter query
|
||||||
filter_query = {}
|
filter_query = {}
|
||||||
|
|
||||||
@@ -91,18 +134,59 @@ def get_plexts_from_db():
|
|||||||
collection = db[collection_name]
|
collection = db[collection_name]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Projection to exclude _id field
|
# Ensure geospatial index exists
|
||||||
projection = {"_id": 0}
|
try:
|
||||||
|
collection.create_index([("coordinates", "2dsphere")], background=True)
|
||||||
|
except PyMongoError as e:
|
||||||
|
logger.warning(f"Could not create geospatial index: {e}")
|
||||||
|
|
||||||
# Execute query with sorting (timestamp DESC - most recent first) and dynamic limit
|
# Execute query based on whether geospatial parameters are provided
|
||||||
cursor = (
|
if center_coords and radius_meters:
|
||||||
collection.find(filter=filter_query, projection=projection)
|
# Use $geoNear aggregation for geospatial query
|
||||||
.sort("timestamp", -1)
|
lat, lng = center_coords
|
||||||
.limit(limit)
|
pipeline = [
|
||||||
)
|
{
|
||||||
|
"$geoNear": {
|
||||||
|
"near": {
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [lng, lat] # GeoJSON uses [longitude, latitude]
|
||||||
|
},
|
||||||
|
"distanceField": "distance", # Add distance to results
|
||||||
|
"maxDistance": radius_meters, # in meters
|
||||||
|
"spherical": True # Use spherical geometry
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$match": filter_query # Apply other filters
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$sort": {"timestamp": -1} # Sort by timestamp (most recent first)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$limit": limit
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$project": {
|
||||||
|
"_id": 0 # Exclude _id field
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
# Convert cursor to list
|
# Execute aggregation pipeline
|
||||||
plexts = list(cursor)
|
plexts = list(collection.aggregate(pipeline))
|
||||||
|
else:
|
||||||
|
# Use standard find() query for non-geospatial queries
|
||||||
|
projection = {"_id": 0}
|
||||||
|
|
||||||
|
# Execute query with sorting (timestamp DESC - most recent first) and dynamic limit
|
||||||
|
cursor = (
|
||||||
|
collection.find(filter=filter_query, projection=projection)
|
||||||
|
.sort("timestamp", -1)
|
||||||
|
.limit(limit)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Convert cursor to list
|
||||||
|
plexts = list(cursor)
|
||||||
|
|
||||||
return jsonify({"count": len(plexts), "plexts": plexts}), 200
|
return jsonify({"count": len(plexts), "plexts": plexts}), 200
|
||||||
|
|
||||||
@@ -237,8 +321,15 @@ def index():
|
|||||||
"timestamp_from": "Minimum timestamp in milliseconds (optional)",
|
"timestamp_from": "Minimum timestamp in milliseconds (optional)",
|
||||||
"timestamp_to": "Maximum timestamp in milliseconds (optional)",
|
"timestamp_to": "Maximum timestamp in milliseconds (optional)",
|
||||||
"limit": "Maximum number of results to return (optional, default: 100)",
|
"limit": "Maximum number of results to return (optional, default: 100)",
|
||||||
|
"center": "Geographic center point in format 'latitude,longitude' (optional, requires radius)",
|
||||||
|
"radius": "Search radius in meters (optional, requires center)",
|
||||||
},
|
},
|
||||||
"authentication": "Basic Auth required",
|
"authentication": "Basic Auth required",
|
||||||
|
"geospatial_query": {
|
||||||
|
"description": "When both center and radius are provided, returns plexts within the specified radius from the center point. If neither is provided, returns all plexts matching other filters.",
|
||||||
|
"example": "center=45.573661,12.365208&radius=1000",
|
||||||
|
"response_field": "distance (meters) - included in results when using geospatial query",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user