diff --git a/packetserver/http/server.py b/packetserver/http/server.py index 9df2b29..9c9b6b3 100644 --- a/packetserver/http/server.py +++ b/packetserver/http/server.py @@ -84,11 +84,69 @@ async def profile(current_user: HttpUser = Depends(get_current_http_user)): } -# Example future endpoint – list recent messages (placeholder) @app.get("/api/v1/messages") -async def list_messages( - limit: int = 20, - current_user: HttpUser = Depends(get_current_http_user) +async def get_messages( + current_user: HttpUser = Depends(get_current_http_user), + type: str = Query("received", description="received, sent, or all"), + limit: Optional[int] = Query(20, le=100, description="Max messages to return (default 20, max 100)"), + since: Optional[str] = Query(None, description="ISO UTC timestamp (e.g. 2025-12-01T00:00:00Z) to filter newer messages") ): - # TODO: implement actual message fetching from ZODB - return {"messages": [], "note": "Not implemented yet"} \ No newline at end of file + """ + List messages for the authenticated user. + - received: incoming (default) + - sent: outgoing (stored in sender's mailbox) + - all: both incoming and outgoing + """ + if limit is None or limit < 1: + limit = 20 + + username = current_user.username # already uppercase + + conn = get_db_connection() + root = conn.root() + + # Ensure mailbox exists (safe, matches server logic) + if 'messages' not in root: + root['messages'] = PersistentMapping() + if username not in root['messages']: + root['messages'][username] = persistent.list.PersistentList() + + mailbox = root['messages'][username] + + # Parse 'since' if provided + since_dt = None + if since: + try: + since_dt = datetime.fromisoformat(since.replace("Z", "+00:00")) + except ValueError: + raise HTTPException(status_code=400, detail="Invalid 'since' format – use ISO UTC (e.g. 2025-12-01T00:00:00Z)") + + messages = [] + for msg in mailbox: + # Filter by type + if type == "received" and msg.msg_from == username: + continue # skip own sent messages + if type == "sent" and msg.msg_from != username: + continue # skip received + # 'all' includes everything + + # Filter by since + if since_dt and msg.sent_at < since_dt: + continue + + # Basic dict (no attachments data yet) + messages.append({ + "id": str(msg.msg_id), + "from": msg.msg_from, + "to": list(msg.msg_to) if isinstance(msg.msg_to, tuple) else [msg.msg_to], + "sent_at": msg.sent_at.isoformat() + "Z", + "text": msg.text, + "has_attachments": len(msg.attachments) > 0, + "retrieved": msg.retrieved # expose if marked read on RF + }) + + # Sort newest first + messages.sort(key=lambda m: m["sent_at"], reverse=True) + + # Apply limit + return {"messages": messages[:limit], "total_returned": len(messages[:limit])} \ No newline at end of file diff --git a/packetserver/runners/http_server.py b/packetserver/runners/http_server.py index b0859f9..b752040 100644 --- a/packetserver/runners/http_server.py +++ b/packetserver/runners/http_server.py @@ -34,8 +34,8 @@ def open_database(db_arg: str) -> ZODB.DB.DB: port = int(port_str) except ValueError: raise ValueError(f"Invalid port in ZEO address: {db_arg}") - storage = ZEO.client_storage(host, port) - return ZODB.DB(storage) + storage = ZEO.DB((host, port)) + return storage else: # Local FileStorage path storage = ZODB.FileStorage.FileStorage(db_arg)