feat: issues board - add submitter name, comments, and edit support

This commit is contained in:
Erik 2026-04-10 17:36:08 +02:00
parent 21e72b438f
commit f96171a345
3 changed files with 313 additions and 28 deletions

47
main.py
View file

@ -1369,6 +1369,7 @@ async def add_issue(issue: dict):
"author": issue.get("author", "Anonymous").strip(),
"created": datetime.utcnow().isoformat(),
"resolved": False,
"comments": [],
}
if not new_issue["title"]:
raise HTTPException(status_code=400, detail="Title is required")
@ -1379,13 +1380,22 @@ async def add_issue(issue: dict):
@app.patch("/issues/{issue_id}")
async def update_issue(issue_id: str, update: dict):
"""Update an issue (e.g. toggle resolved state)."""
"""Update an issue (toggle resolved, edit title/description/category)."""
issues = _load_issues()
found = None
for i in issues:
if i.get("id") == issue_id:
if "resolved" in update:
i["resolved"] = bool(update["resolved"])
if "title" in update:
title = update["title"].strip()
if not title:
raise HTTPException(status_code=400, detail="Title cannot be empty")
i["title"] = title
if "description" in update:
i["description"] = update["description"].strip()
if "category" in update:
i["category"] = update["category"]
found = i
break
if not found:
@ -1394,6 +1404,33 @@ async def update_issue(issue_id: str, update: dict):
return found
@app.post("/issues/{issue_id}/comments")
async def add_comment(issue_id: str, comment: dict):
"""Add a comment to an issue."""
issues = _load_issues()
found = None
for i in issues:
if i.get("id") == issue_id:
found = i
break
if not found:
raise HTTPException(status_code=404, detail="Issue not found")
text = comment.get("text", "").strip()
if not text:
raise HTTPException(status_code=400, detail="Comment text is required")
new_comment = {
"id": uuid.uuid4().hex[:8],
"author": comment.get("author", "Anonymous").strip(),
"text": text,
"created": datetime.utcnow().isoformat(),
}
if "comments" not in found:
found["comments"] = []
found["comments"].append(new_comment)
_save_issues(issues)
return new_comment
@app.delete("/issues/{issue_id}")
async def delete_issue(issue_id: str):
"""Permanently delete an issue."""
@ -2768,7 +2805,9 @@ async def ws_receive_snapshots(
landblock = data.get("landblock")
if landblock:
dungeon_map_cache[landblock] = data
logger.info(f"Cached dungeon map for {landblock} ({len(data.get('z_levels', []))} z-levels)")
logger.info(
f"Cached dungeon map for {landblock} ({len(data.get('z_levels', []))} z-levels)"
)
await _broadcast_to_browser_clients(data)
continue
# Unknown message types are ignored
@ -3328,7 +3367,9 @@ class NoCacheStaticFiles(StaticFiles):
# Check content-type header since root path "" resolves to index.html
# via html=True and we need to catch it too.
ct = response.headers.get("content-type", "").lower()
if any(t in ct for t in ("text/html", "javascript", "text/css", "application/json")):
if any(
t in ct for t in ("text/html", "javascript", "text/css", "application/json")
):
response.headers["Cache-Control"] = "no-cache, must-revalidate"
return response