Revert "message pagination"

This reverts commit fd9d113eef.
This commit is contained in:
Michael Woods
2025-12-28 19:14:48 -05:00
parent fd9d113eef
commit f8305945a4
2 changed files with 41 additions and 139 deletions

View File

@@ -1,5 +1,5 @@
# packetserver/http/routers/messages.py # packetserver/http/routers/messages.py
from fastapi import APIRouter, Depends, Query, HTTPException, Path, Request, Query from fastapi import APIRouter, Depends, Query, HTTPException, Path, Request
from fastapi.responses import HTMLResponse from fastapi.responses import HTMLResponse
from typing import Optional from typing import Optional
from datetime import datetime from datetime import datetime
@@ -11,7 +11,6 @@ from pydantic import BaseModel, Field, validator
from packetserver.http.dependencies import get_current_http_user from packetserver.http.dependencies import get_current_http_user
from packetserver.http.auth import HttpUser from packetserver.http.auth import HttpUser
from packetserver.http.database import DbDependency from packetserver.http.database import DbDependency
from packetserver.http.server import templates
html_router = APIRouter(tags=["messages-html"]) html_router = APIRouter(tags=["messages-html"])
@@ -28,78 +27,58 @@ class MarkRetrievedRequest(BaseModel):
return v return v
@router.get("/messages", response_class=HTMLResponse) @router.get("/messages")
async def message_list( async def get_messages(
request: Request,
db: DbDependency, db: DbDependency,
current_user: HttpUser = Depends(get_current_http_user), current_user: HttpUser = Depends(get_current_http_user),
msg_type: str = Query("received", alias="type"), # received, sent, all type: str = Query("received", description="received, sent, or all"),
search: Optional[str] = Query(None), limit: Optional[int] = Query(20, le=100, description="Max messages to return (default 20, max 100)"),
page: int = Query(1, ge=1), since: Optional[str] = Query(None, description="ISO UTC timestamp filter (e.g. 2025-12-01T00:00:00Z)"),
per_page: int = Query(50, ge=1, le=200),
): ):
username = current_user.username.upper().strip() if limit is None or limit < 1:
limit = 20
valid_types = {"received", "sent", "all"}
if msg_type not in valid_types:
msg_type = "received"
username = current_user.username
with db.transaction() as conn: with db.transaction() as conn:
root = conn.root() root = conn.root()
user_messages = root["messages"].get(username, [])
# Convert to list of dicts (as current code does) if 'messages' not in root:
root['messages'] = PersistentMapping()
if username not in root['messages']:
root['messages'][username] = persistent.list.PersistentList()
mailbox = root['messages'][username]
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")
messages = [] messages = []
for msg_id, msg in user_messages.items(): for msg in mailbox:
if type == "received" and msg.msg_from == username:
continue
if type == "sent" and msg.msg_from != username:
continue
if since_dt and msg.sent_at < since_dt:
continue
messages.append({ messages.append({
"id": msg_id, "id": str(msg.msg_id),
"from": msg["from"], "from": msg.msg_from,
"to": msg["to"], "to": list(msg.msg_to) if isinstance(msg.msg_to, tuple) else [msg.msg_to],
"text": msg["text"], "sent_at": msg.sent_at.isoformat() + "Z",
"timestamp": msg["timestamp"], "text": msg.text,
"has_attachments": len(msg.attachments) > 0,
"retrieved": msg.retrieved,
}) })
# Filter by type messages.sort(key=lambda m: m["sent_at"], reverse=True)
if msg_type == "received":
filtered = [m for m in messages if username in m["to"]]
elif msg_type == "sent":
filtered = [m for m in messages if m["from"] == username]
else: # all
filtered = messages
# Apply search return {"messages": messages[:limit], "total_returned": len(messages[:limit])}
if search:
search_lower = search.strip().lower()
filtered = [
m for m in filtered
if (search_lower in m["from"].lower() or
any(search_lower in t.lower() for t in m["to"]) or
search_lower in m["text"].lower())
]
# Sort newest first
filtered.sort(key=lambda m: m["timestamp"], reverse=True)
# Pagination
total = len(filtered)
start = (page - 1) * per_page
paginated = filtered[start:start + per_page]
total_pages = (total + per_page - 1) // per_page
return templates.TemplateResponse(
"message_list.html",
{
"request": request,
"messages": paginated,
"current_user": current_user,
"total": total,
"page": page,
"per_page": per_page,
"total_pages": total_pages,
"current_type": msg_type,
"current_search": search,
}
)
@router.get("/messages/{msg_id}") @router.get("/messages/{msg_id}")
async def get_message( async def get_message(

View File

@@ -10,45 +10,6 @@
</button> </button>
</div> </div>
<div class="d-flex justify-content-between align-items-center mb-4 flex-wrap gap-3">
<!-- Type tabs -->
<ul class="nav nav-tabs">
<li class="nav-item">
<a class="nav-link {% if current_type == 'received' %}active{% endif %}"
href="?type=received{% if current_search %}&search={{ current_search }}{% endif %}">Received</a>
</li>
<li class="nav-item">
<a class="nav-link {% if current_type == 'sent' %}active{% endif %}"
href="?type=sent{% if current_search %}&search={{ current_search }}{% endif %}">Sent</a>
</li>
<li class="nav-item">
<a class="nav-link {% if current_type == 'all' %}active{% endif %}"
href="?type=all{% if current_search %}&search={{ current_search }}{% endif %}">All</a>
</li>
</ul>
<!-- Search form -->
<form method="get" class="d-flex">
<input type="hidden" name="type" value="{{ current_type }}">
<input type="text" name="search" class="form-control me-2" placeholder="Search messages..."
value="{{ current_search or '' }}">
<button type="submit" class="btn btn-outline-primary">Search</button>
{% if current_search %}
<a href="?type={{ current_type }}" class="btn btn-outline-secondary ms-2">Clear</a>
{% endif %}
</form>
</div>
{% if total == 0 %}
<div class="alert alert-info">
{% if current_search %}
No messages found matching "{{ current_search }}".
{% else %}
No messages yet.
{% endif %}
</div>
{% endif %}
<div class="mb-3"> <div class="mb-3">
<a href="?msg_type=received" class="btn btn-sm {% if msg_type == 'received' %}btn-primary{% else %}btn-outline-primary{% endif %}">Received</a> <a href="?msg_type=received" class="btn btn-sm {% if msg_type == 'received' %}btn-primary{% else %}btn-outline-primary{% endif %}">Received</a>
<a href="?msg_type=sent" class="btn btn-sm {% if msg_type == 'sent' %}btn-primary{% else %}btn-outline-primary{% endif %}">Sent</a> <a href="?msg_type=sent" class="btn btn-sm {% if msg_type == 'sent' %}btn-primary{% else %}btn-outline-primary{% endif %}">Sent</a>
@@ -56,9 +17,6 @@
</div> </div>
{% if messages %} {% if messages %}
<p class="text-muted text-center mb-3">
Showing {{ (page-1)*per_page + 1 }}{{ min(page*per_page, total) }} of {{ total }} messages
</p>
<ul class="message-list"> <ul class="message-list">
{% for msg in messages %} {% for msg in messages %}
<li> <li>
@@ -72,41 +30,6 @@
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
{% if total_pages > 1 %}
<nav aria-label="Message pagination" class="mt-4">
<ul class="pagination justify-content-center">
<!-- Previous -->
<li class="page-item {% if page == 1 %}disabled{% endif %}">
<a class="page-link" href="?page={{ page - 1 }}&type={{ current_type }}{% if current_search %}&search={{ current_search }}{% endif %}">Previous</a>
</li>
<!-- Page numbers (simple: show current ±2, plus first/last) -->
{% set nearby = range(max(1, page-2), min(total_pages+1, page+3)) %}
{% if 1 not in nearby %}
<li class="page-item"><a class="page-link" href="?page=1&type={{ current_type }}{% if current_search %}&search={{ current_search }}{% endif %}">1</a></li>
{% if page > 4 %}<li class="page-item disabled"><span class="page-link">...</span></li>{% endif %}
{% endif %}
{% for p in nearby %}
<li class="page-item {% if p == page %}active{% endif %}">
<a class="page-link" href="?page={{ p }}&type={{ current_type }}{% if current_search %}&search={{ current_search }}{% endif %}">{{ p }}</a>
</li>
{% endfor %}
{% if total_pages not in nearby %}
{% if page < total_pages - 3 %}<li class="page-item disabled"><span class="page-link">...</span></li>{% endif %}
<li class="page-item"><a class="page-link" href="?page={{ total_pages }}&type={{ current_type }}{% if current_search %}&search={{ current_search }}{% endif %}">{{ total_pages }}</a></li>
{% endif %}
<!-- Next -->
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
<a class="page-link" href="?page={{ page + 1 }}&type={{ current_type }}{% if current_search %}&search={{ current_search }}{% endif %}">Next</a>
</li>
</ul>
</nav>
{% endif %}
{% else %} {% else %}
<p>No messages found.</p> <p>No messages found.</p>
{% endif %} {% endif %}