from fastapi import APIRouter, HTTPException from database import events_collection router = APIRouter() @router.get("/events") def list_events( service: str = None, actor: str = None, operation: str = None, result: str = None, start: str = None, end: str = None, search: str = None, page: int = 1, page_size: int = 50, ): filters = [] if service: filters.append({"service": service}) if actor: filters.append( { "$or": [ {"actor_display": {"$regex": actor, "$options": "i"}}, {"actor_upn": {"$regex": actor, "$options": "i"}}, {"actor.user.userPrincipalName": {"$regex": actor, "$options": "i"}}, {"actor.user.id": actor}, ] } ) if operation: filters.append({"operation": {"$regex": operation, "$options": "i"}}) if result: filters.append({"result": {"$regex": result, "$options": "i"}}) if start or end: time_filter = {} if start: time_filter["$gte"] = start if end: time_filter["$lte"] = end filters.append({"timestamp": time_filter}) if search: filters.append( { "$or": [ {"raw_text": {"$regex": search, "$options": "i"}}, {"display_summary": {"$regex": search, "$options": "i"}}, {"actor_display": {"$regex": search, "$options": "i"}}, {"target_displays": {"$elemMatch": {"$regex": search, "$options": "i"}}}, {"operation": {"$regex": search, "$options": "i"}}, ] } ) query = {"$and": filters} if filters else {} safe_page_size = max(1, min(page_size, 500)) safe_page = max(1, page) skip = (safe_page - 1) * safe_page_size try: total = events_collection.count_documents(query) cursor = events_collection.find(query).sort("timestamp", -1).skip(skip).limit(safe_page_size) events = list(cursor) except Exception as exc: raise HTTPException(status_code=500, detail=f"Failed to query events: {exc}") from exc for e in events: e["_id"] = str(e["_id"]) return { "items": events, "total": total, "page": safe_page, "page_size": safe_page_size, } @router.get("/filter-options") def filter_options(limit: int = 200): """ Provide distinct values for UI filters (best-effort, capped). """ safe_limit = max(1, min(limit, 1000)) try: services = sorted(events_collection.distinct("service"))[:safe_limit] operations = sorted(events_collection.distinct("operation"))[:safe_limit] results = sorted([r for r in events_collection.distinct("result") if r])[:safe_limit] actors = sorted([a for a in events_collection.distinct("actor_display") if a])[:safe_limit] actor_upns = sorted([a for a in events_collection.distinct("actor_upn") if a])[:safe_limit] devices = sorted([a for a in events_collection.distinct("target_displays") if isinstance(a, str)])[:safe_limit] except Exception as exc: raise HTTPException(status_code=500, detail=f"Failed to load filter options: {exc}") from exc return { "services": services, "operations": operations, "results": results, "actors": actors, "actor_upns": actor_upns, "devices": devices, }