feat(meeting-intelligence): add conference_prefix filter for space-scoped meetings

Adds optional conference_prefix query param to GET /meetings that filters
by conference_id LIKE prefix%. This enables rMeets to scope MI data per space.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-04-10 18:37:25 -04:00
parent 2984a2944c
commit 1706dc47a3
2 changed files with 61 additions and 43 deletions

View File

@ -48,29 +48,37 @@ class Database:
self, self,
limit: int = 50, limit: int = 50,
offset: int = 0, offset: int = 0,
status: Optional[str] = None status: Optional[str] = None,
conference_prefix: Optional[str] = None
) -> List[Dict[str, Any]]: ) -> List[Dict[str, Any]]:
"""List meetings with pagination.""" """List meetings with pagination. Optionally filter by conference_id prefix."""
async with self.pool.acquire() as conn: async with self.pool.acquire() as conn:
conditions = []
params: list = []
idx = 1
if status: if status:
rows = await conn.fetch(""" conditions.append(f"status = ${idx}")
SELECT id, conference_id, conference_name, title, params.append(status)
started_at, ended_at, duration_seconds, idx += 1
status, created_at
FROM meetings if conference_prefix:
WHERE status = $1 conditions.append(f"conference_id LIKE ${idx}")
ORDER BY created_at DESC params.append(conference_prefix + "%")
LIMIT $2 OFFSET $3 idx += 1
""", status, limit, offset)
else: where = f"WHERE {' AND '.join(conditions)}" if conditions else ""
rows = await conn.fetch(""" params.extend([limit, offset])
SELECT id, conference_id, conference_name, title,
started_at, ended_at, duration_seconds, rows = await conn.fetch(f"""
status, created_at SELECT id, conference_id, conference_name, title,
FROM meetings started_at, ended_at, duration_seconds,
ORDER BY created_at DESC status, created_at
LIMIT $1 OFFSET $2 FROM meetings
""", limit, offset) {where}
ORDER BY created_at DESC
LIMIT ${idx} OFFSET ${idx + 1}
""", *params)
return [dict(row) for row in rows] return [dict(row) for row in rows]
@ -156,33 +164,40 @@ class Database:
tokens: List[str], tokens: List[str],
limit: int = 50, limit: int = 50,
offset: int = 0, offset: int = 0,
status: Optional[str] = None status: Optional[str] = None,
conference_prefix: Optional[str] = None
) -> List[Dict[str, Any]]: ) -> List[Dict[str, Any]]:
"""List meetings filtered by access tokens.""" """List meetings filtered by access tokens. Optionally filter by conference_id prefix."""
if not tokens: if not tokens:
return [] return []
async with self.pool.acquire() as conn: async with self.pool.acquire() as conn:
conditions = ["access_token = ANY($1)"]
params: list = [tokens]
idx = 2
if status: if status:
rows = await conn.fetch(""" conditions.append(f"status = ${idx}")
SELECT id, conference_id, conference_name, title, params.append(status)
started_at, ended_at, duration_seconds, idx += 1
status, created_at
FROM meetings if conference_prefix:
WHERE access_token = ANY($1) AND status = $2 conditions.append(f"conference_id LIKE ${idx}")
ORDER BY created_at DESC params.append(conference_prefix + "%")
LIMIT $3 OFFSET $4 idx += 1
""", tokens, status, limit, offset)
else: where = " AND ".join(conditions)
rows = await conn.fetch(""" params.extend([limit, offset])
SELECT id, conference_id, conference_name, title,
started_at, ended_at, duration_seconds, rows = await conn.fetch(f"""
status, created_at SELECT id, conference_id, conference_name, title,
FROM meetings started_at, ended_at, duration_seconds,
WHERE access_token = ANY($1) status, created_at
ORDER BY created_at DESC FROM meetings
LIMIT $2 OFFSET $3 WHERE {where}
""", tokens, limit, offset) ORDER BY created_at DESC
LIMIT ${idx} OFFSET ${idx + 1}
""", *params)
return [dict(row) for row in rows] return [dict(row) for row in rows]

View File

@ -76,12 +76,14 @@ async def list_meetings(
request: Request, request: Request,
limit: int = Query(default=50, le=100), limit: int = Query(default=50, le=100),
offset: int = Query(default=0, ge=0), offset: int = Query(default=0, ge=0),
status: Optional[str] = Query(default=None) status: Optional[str] = Query(default=None),
conference_prefix: Optional[str] = Query(default=None, description="Filter by conference_id prefix (e.g. space slug)")
): ):
"""List meetings the caller has access to. """List meetings the caller has access to.
Requires X-MI-Tokens header with comma-separated access tokens. Requires X-MI-Tokens header with comma-separated access tokens.
Returns only meetings matching the provided tokens. Returns only meetings matching the provided tokens.
Optionally filter by conference_prefix to scope to a space.
""" """
db = request.app.state.db db = request.app.state.db
tokens = get_multi_tokens(request) tokens = get_multi_tokens(request)
@ -90,7 +92,8 @@ async def list_meetings(
return MeetingListResponse(meetings=[], total=0, limit=limit, offset=offset) return MeetingListResponse(meetings=[], total=0, limit=limit, offset=offset)
meetings = await db.list_meetings_by_tokens( meetings = await db.list_meetings_by_tokens(
tokens=tokens, limit=limit, offset=offset, status=status tokens=tokens, limit=limit, offset=offset, status=status,
conference_prefix=conference_prefix
) )
return MeetingListResponse( return MeetingListResponse(