add endpoint for mongo results (basic auth)

This commit is contained in:
Matteo Rosati
2026-01-15 12:28:32 +01:00
parent 4af1996fb4
commit ce868e1807

152
app.py
View File

@@ -2,9 +2,12 @@ import os
import logging import logging
from datetime import datetime from datetime import datetime
from zoneinfo import ZoneInfo from zoneinfo import ZoneInfo
from flask import Flask, request, jsonify from functools import wraps
from flask import Flask, request, jsonify, Response
from ingress import IngressAPI from ingress import IngressAPI
from models import EventType, Plext from models import EventType, Plext
from pymongo import MongoClient
from pymongo.errors import PyMongoError
# Timezone configuration # Timezone configuration
TIMEZONE = ZoneInfo("Europe/Rome") TIMEZONE = ZoneInfo("Europe/Rome")
@@ -18,6 +21,51 @@ logger = logging.getLogger(__name__)
app = Flask(__name__) app = Flask(__name__)
def check_basic_auth(username: str, password: str) -> bool:
"""
Check if the provided username and password match the configured credentials.
Args:
username: Username from the request
password: Password from the request
Returns:
True if credentials match, False otherwise
"""
expected_username = os.getenv("BASIC_AUTH_USER")
expected_password = os.getenv("BASIC_AUTH_PASSWORD")
if not expected_username or not expected_password:
logger.warning("BASIC_AUTH_USER or BASIC_AUTH_PASSWORD not configured")
return False
return username == expected_username and password == expected_password
def basic_auth_required(f):
"""
Decorator to require basic authentication for an endpoint.
Returns:
401 Unauthorized if authentication fails or is missing
"""
@wraps(f)
def decorated(*args, **kwargs):
auth = request.authorization
if not auth or not check_basic_auth(auth.username, auth.password):
return Response(
"Could not verify your access level for that URL.\n"
"You have to login with proper credentials",
401,
{"WWW-Authenticate": 'Basic realm="Login Required"'}
)
return f(*args, **kwargs)
return decorated
def parse_timestamp(value: str) -> int: def parse_timestamp(value: str) -> int:
""" """
Parse timestamp from either milliseconds (int) or ISO 8601 string. Parse timestamp from either milliseconds (int) or ISO 8601 string.
@@ -102,9 +150,93 @@ def plext_to_dict(plext: Plext) -> dict:
], ],
} }
@app.route("/plexts/from-db", methods=["GET"])
@basic_auth_required
def get_plexts_from_db():
"""
Get plexts from MongoDB with optional filters.
@app.route("/plexts", methods=["GET"]) Query Parameters:
def get_plexts(): player_name: Filter by player name (optional)
timestamp_from: Minimum timestamp in milliseconds (optional)
timestamp_to: Maximum timestamp in milliseconds (optional)
Returns:
JSON response with list of plexts (without _id field)
"""
try:
# Parse query parameters
player_name = request.args.get("player_name")
timestamp_from = request.args.get("timestamp_from")
timestamp_to = request.args.get("timestamp_to")
# Validate and convert timestamp parameters to integers if provided
if timestamp_from is not None:
try:
timestamp_from = int(timestamp_from)
except ValueError:
return jsonify({"error": "timestamp_from must be an integer"}), 400
if timestamp_to is not None:
try:
timestamp_to = int(timestamp_to)
except ValueError:
return jsonify({"error": "timestamp_to must be an integer"}), 400
# Build MongoDB filter query
filter_query = {}
if player_name:
filter_query["player_name"] = player_name
if timestamp_from is not None:
filter_query["timestamp"] = filter_query.get("timestamp", {})
filter_query["timestamp"]["$gte"] = timestamp_from
if timestamp_to is not None:
filter_query["timestamp"] = filter_query.get("timestamp", {})
filter_query["timestamp"]["$lte"] = timestamp_to
# Connect to MongoDB
mongo_uri = os.getenv("MONGO_URI")
db_name = os.getenv("DB_NAME")
collection_name = os.getenv("COLLECTION_NAME")
client = MongoClient(mongo_uri)
db = client[db_name]
collection = db[collection_name]
try:
# Projection to exclude _id field
projection = {"_id": 0}
# Execute query with sorting (timestamp DESC - most recent first)
cursor = collection.find(
filter=filter_query,
projection=projection
).sort("timestamp", -1)
# Convert cursor to list
plexts = list(cursor)
return jsonify({
"count": len(plexts),
"plexts": plexts
})
except PyMongoError as e:
logger.error(f"MongoDB error: {e}")
return jsonify({"error": "Database error"}), 500
finally:
client.close()
except Exception as e:
logger.exception("Unexpected error in get_plexts_from_db")
return jsonify({"error": "An error occurred"}), 500
@app.route("/plexts/from-api", methods=["GET"])
@basic_auth_required
def get_plexts_from_api():
""" """
Get plexts from the Ingress API. Get plexts from the Ingress API.
@@ -199,7 +331,7 @@ def index():
"name": "Ingress Intel API", "name": "Ingress Intel API",
"version": "1.0.0", "version": "1.0.0",
"endpoints": { "endpoints": {
"/plexts": { "/plexts/from-api": {
"method": "GET", "method": "GET",
"description": "Get plexts from the Ingress API", "description": "Get plexts from the Ingress API",
"parameters": { "parameters": {
@@ -213,7 +345,17 @@ def index():
"max_timestamp": "Maximum timestamp (milliseconds or ISO 8601 format, default: -1)", "max_timestamp": "Maximum timestamp (milliseconds or ISO 8601 format, default: -1)",
}, },
"event_types": [e.name for e in EventType], "event_types": [e.name for e in EventType],
} },
"/plexts/from-db": {
"method": "GET",
"description": "Get plexts from MongoDB with optional filters",
"parameters": {
"player_name": "Filter by player name (optional)",
"timestamp_from": "Minimum timestamp in milliseconds (optional)",
"timestamp_to": "Maximum timestamp in milliseconds (optional)",
},
"authentication": "Basic Auth required",
},
}, },
} }
) )