diff --git a/Dockerfile b/Dockerfile index 6c491936..9df47396 100644 --- a/Dockerfile +++ b/Dockerfile @@ -29,6 +29,10 @@ COPY Dockerfile /Dockerfile ## Expose the application port to host EXPOSE 8765 +## Build version (CalVer + git hash, set via --build-arg) +ARG BUILD_VERSION=dev +ENV APP_VERSION=$BUILD_VERSION + ## Default environment variables for application configuration ENV DATABASE_URL=postgresql://postgres:password@db:5432/dereth \ DB_MAX_SIZE_MB=2048 \ diff --git a/main.py b/main.py index 24f9ccba..3327c5d1 100644 --- a/main.py +++ b/main.py @@ -10,6 +10,7 @@ from datetime import datetime, timedelta, timezone import json import logging import os +import uuid import sys import time from typing import Dict, List, Any @@ -1326,6 +1327,64 @@ async def get_recent_activity(): raise HTTPException(status_code=500, detail="Internal server error") +# ─── Version endpoint ──────────────────────────────────────────── +@app.get("/api-version") +async def get_version(): + """Return the application version (CalVer + git hash, set at build time).""" + return {"version": os.environ.get("APP_VERSION", "dev")} + + +# ─── Issues board endpoints ────────────────────────────────────── +ISSUES_FILE = Path("openissues.json") + + +def _load_issues(): + if ISSUES_FILE.exists(): + try: + return json.loads(ISSUES_FILE.read_text()) + except (json.JSONDecodeError, IOError): + pass + return [] + + +def _save_issues(issues): + ISSUES_FILE.write_text(json.dumps(issues, indent=2)) + + +@app.get("/issues") +async def get_issues(): + """Return all open issues.""" + return {"issues": _load_issues()} + + +@app.post("/issues") +async def add_issue(issue: dict): + """Add a new issue.""" + issues = _load_issues() + new_issue = { + "id": uuid.uuid4().hex[:8], + "title": issue.get("title", "").strip(), + "description": issue.get("description", "").strip(), + "category": issue.get("category", "other"), + "author": issue.get("author", "Anonymous").strip(), + "created": datetime.utcnow().isoformat(), + } + if not new_issue["title"]: + raise HTTPException(status_code=400, detail="Title is required") + issues.insert(0, new_issue) + _save_issues(issues) + return new_issue + + +@app.delete("/issues/{issue_id}") +async def delete_issue(issue_id: str): + """Resolve (delete) an issue.""" + issues = _load_issues() + issues = [i for i in issues if i.get("id") != issue_id] + _save_issues(issues) + return {"status": "ok"} + + @app.get("/server-health") async def get_server_health(): """Return current server health status.""" diff --git a/static/index.html b/static/index.html index 066658b7..e408b3fd 100644 --- a/static/index.html +++ b/static/index.html @@ -12,6 +12,9 @@
+ + +