More bulletins changes.

This commit is contained in:
Michael Woods
2025-12-24 19:56:18 -05:00
parent 31ea05e3cb
commit 25345d8aff

View File

@@ -1,61 +1,81 @@
from fastapi import APIRouter, Path, Query, Depends, HTTPException, Request, status
from fastapi.responses import HTMLResponse
from typing import Optional
from typing import Optional, List
from pydantic import BaseModel, Field, constr
from datetime import datetime
import transaction
from persistent.list import PersistentList
from ..dependencies import get_current_http_user # relative
from ..dependencies import get_current_http_user
from ..auth import HttpUser
from ..server import templates # relative import - this is now safe
from ..server import templates
from packetserver.runners.http_server import get_db_connection
from packetserver.server.bulletin import Bulletin
# Existing API router (keep)
# API router (/api/v1)
router = APIRouter(prefix="/api/v1", tags=["bulletins"])
# ... your existing list_bulletins and get_bulletin routes ...
# New non-prefixed router for HTML pages
# HTML router (pretty URLs: /bulletins, /bulletins/{bid})
html_router = APIRouter(tags=["bulletins-html"])
@html_router.get("/bulletins", response_class="HTMLResponse")
async def bulletin_list_page(request: Request, limit: Optional[int] = Query(50, le=100)):
# Local import to avoid circular issues
from .bulletins import list_bulletins as api_list_bulletins
api_resp = await api_list_bulletins(limit=limit, since=None)
bulletins = api_resp["bulletins"]
# --- API Endpoints ---
current_user = None
try:
current_user = await get_current_http_user()(request) # optional call
except:
pass
async def list_bulletins(limit: int = 50, since: Optional[datetime] = None) -> dict:
conn = get_db_connection()
root = conn.root()
bulletins_list: List[Bulletin] = root.get("bulletins", [])
return templates.TemplateResponse(
"bulletin_list.html",
{"request": request, "bulletins": bulletins, "current_user": current_user.username if current_user else None}
)
# Newest first
bulletins_list = sorted(bulletins_list, key=lambda b: b.created_at, reverse=True)
@html_router.get("/bulletins/{bid}", response_class="HTMLResponse")
async def bulletin_detail_page(request: Request, bid: int):
from .bulletins import get_bulletin as api_get_bulletin
try:
bulletin = await api_get_bulletin(bid=bid, current_user=None)
except HTTPException:
if since:
bulletins_list = [b for b in bulletins_list if b.created_at > since]
bulletins = [
{
"id": b.id,
"author": b.author,
"subject": b.subject,
"body": b.body,
"created_at": b.created_at.isoformat() + "Z",
"updated_at": b.updated_at.isoformat() + "Z",
}
for b in bulletins_list[:limit]
]
return {"bulletins": bulletins}
@router.get("/bulletins")
async def api_list_bulletins(
limit: Optional[int] = Query(50, le=100),
since: Optional[datetime] = None,
current_user: HttpUser = Depends(get_current_http_user)
):
return await list_bulletins(limit=limit, since=since)
async def get_one_bulletin(bid: int) -> dict:
conn = get_db_connection()
root = conn.root()
bulletins_list: List[Bulletin] = root.get("bulletins", [])
for b in bulletins_list:
if b.id == bid:
return {
"id": b.id,
"author": b.author,
"subject": b.subject,
"body": b.body,
"created_at": b.created_at.isoformat() + "Z",
"updated_at": b.updated_at.isoformat() + "Z",
}
raise HTTPException(status_code=404, detail="Bulletin not found")
current_user = None
try:
current_user = await get_current_http_user()(request)
except:
pass
return templates.TemplateResponse(
"bulletin_detail.html",
{"request": request, "bulletin": bulletin, "current_user": current_user.username if current_user else None}
)
@router.get("/bulletins/{bid}")
async def api_get_bulletin(
bid: int,
current_user: HttpUser = Depends(get_current_http_user)
):
return await get_one_bulletin(bid)
class CreateBulletinRequest(BaseModel):
subject: constr(min_length=1, max_length=100) = Field(..., description="Bulletin subject/title")
@@ -66,29 +86,24 @@ async def create_bulletin(
payload: CreateBulletinRequest,
current_user: HttpUser = Depends(get_current_http_user)
):
from packetserver.runners.http_server import get_db_connection
from packetserver.server.bulletin import Bulletin
conn = get_db_connection()
root = conn.root()
# Ensure the bulletins list and counter exist
if 'bulletins' not in root:
root['bulletins'] = PersistentList()
new_bulletin = Bulletin(
author=current_user.username, # uppercase callsign
author=current_user.username,
subject=payload.subject.strip(),
text=payload.body.strip() # note: 'text' param, assigned to body
text=payload.body.strip()
)
# This assigns the ID, sets timestamps (if not already), and appends
new_id = new_bulletin.write_new(root)
transaction.commit()
return {
"id": new_id, # or new_bulletin.id
"id": new_id,
"author": new_bulletin.author,
"subject": new_bulletin.subject,
"body": new_bulletin.body,
@@ -96,32 +111,31 @@ async def create_bulletin(
"updated_at": new_bulletin.updated_at.isoformat() + "Z",
}
# --- HTML Pages (require login) ---
@html_router.get("/bulletins", response_class=HTMLResponse)
async def bulletin_list_page(
request: Request,
limit: Optional[int] = Query(50, le=100),
current_user: Optional[HttpUser] = Depends(get_current_http_user, use_cache=False) # optional auth
current_user: HttpUser = Depends(get_current_http_user)
):
# Internal call to existing API function
api_resp = await list_bulletins(limit=limit, since=None)
bulletins = api_resp["bulletins"]
return templates.TemplateResponse(
"bulletin_list.html",
{"request": request, "bulletins": bulletins, "current_user": current_user.username if current_user else None}
{"request": request, "bulletins": bulletins, "current_user": current_user.username}
)
@html_router.get("/bulletins/{bid}", response_class=HTMLResponse)
async def bulletin_detail_page(
request: Request,
bid: int = Path(...),
current_user: Optional[HttpUser] = Depends(get_current_http_user, use_cache=False)
current_user: HttpUser = Depends(get_current_http_user)
):
# Internal call to existing detail function
# Pass a dummy None user since the API requires it but doesn't enforce privileges
bulletin = await get_bulletin(bid=bid, current_user=None)
bulletin = await get_one_bulletin(bid=bid)
return templates.TemplateResponse(
"bulletin_detail.html",
{"request": request, "bulletin": bulletin, "current_user": current_user.username if current_user else None}
{"request": request, "bulletin": bulletin, "current_user": current_user.username}
)