Add suggestions feature: Gitea-backed feedback → issues
This commit is contained in:
121
suggestions/routes_fastapi.py
Normal file
121
suggestions/routes_fastapi.py
Normal file
@@ -0,0 +1,121 @@
|
||||
"""
|
||||
FastAPI adapter for the Gitea-backed suggestions module.
|
||||
|
||||
Use this INSTEAD of routes_flask.py if the app is FastAPI. Wire it in with:
|
||||
|
||||
from suggestions.routes_fastapi import router as suggestions_router
|
||||
app.include_router(suggestions_router)
|
||||
|
||||
AUTH: replace `current_user()` with the app's real dependency. It must return
|
||||
something exposing `.name` and `.email`, or None.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import APIRouter, File, Request, UploadFile
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
from .gitea import (
|
||||
ALLOWED_IMAGE_TYPES,
|
||||
MAX_UPLOAD_BYTES,
|
||||
GiteaClient,
|
||||
GiteaError,
|
||||
footer,
|
||||
gitea_config,
|
||||
save_upload,
|
||||
sniff_image,
|
||||
)
|
||||
|
||||
router = APIRouter()
|
||||
UPLOAD_DIR = Path("/data/uploads/suggestions")
|
||||
|
||||
|
||||
def current_user():
|
||||
"""ADAPT THIS to the app's real auth. Return obj with .name/.email or None."""
|
||||
return type("U", (), {"name": "Household", "email": "household@local"})()
|
||||
|
||||
|
||||
def _client_or_error():
|
||||
cfg = gitea_config()
|
||||
if not cfg:
|
||||
return None, JSONResponse({"error": "not_configured"}, status_code=503)
|
||||
return GiteaClient(cfg), None
|
||||
|
||||
|
||||
@router.get("/api/suggestions")
|
||||
def list_suggestions(state: str = "open"):
|
||||
if current_user() is None:
|
||||
return JSONResponse({"error": "unauthorized"}, status_code=401)
|
||||
client, err = _client_or_error()
|
||||
if err:
|
||||
return err
|
||||
try:
|
||||
return {"issues": client.list_issues(state)}
|
||||
except GiteaError as e:
|
||||
return JSONResponse({"error": str(e)}, status_code=502)
|
||||
|
||||
|
||||
@router.post("/api/suggestions")
|
||||
async def create_suggestion(request: Request):
|
||||
user = current_user()
|
||||
if user is None:
|
||||
return JSONResponse({"error": "unauthorized"}, status_code=401)
|
||||
client, err = _client_or_error()
|
||||
if err:
|
||||
return err
|
||||
data = await request.json()
|
||||
title = (data.get("title") or "").strip()
|
||||
if len(title) < 3:
|
||||
return JSONResponse({"error": "title_required"}, status_code=400)
|
||||
body = (data.get("body") or "").strip() + footer(user.name, user.email)
|
||||
try:
|
||||
return JSONResponse({"issue": client.create_issue(title, body)}, status_code=201)
|
||||
except GiteaError as e:
|
||||
return JSONResponse({"error": str(e)}, status_code=502)
|
||||
|
||||
|
||||
@router.get("/api/suggestions/{number}/comments")
|
||||
def list_comments(number: int):
|
||||
if current_user() is None:
|
||||
return JSONResponse({"error": "unauthorized"}, status_code=401)
|
||||
client, err = _client_or_error()
|
||||
if err:
|
||||
return err
|
||||
try:
|
||||
return {"comments": client.list_comments(number)}
|
||||
except GiteaError as e:
|
||||
return JSONResponse({"error": str(e)}, status_code=502)
|
||||
|
||||
|
||||
@router.post("/api/suggestions/{number}/comments")
|
||||
async def add_comment(number: int, request: Request):
|
||||
user = current_user()
|
||||
if user is None:
|
||||
return JSONResponse({"error": "unauthorized"}, status_code=401)
|
||||
client, err = _client_or_error()
|
||||
if err:
|
||||
return err
|
||||
data = await request.json()
|
||||
text = (data.get("body") or "").strip()
|
||||
if not text:
|
||||
return JSONResponse({"error": "body_required"}, status_code=400)
|
||||
text += f"\n\n_— {user.name}_"
|
||||
try:
|
||||
return JSONResponse({"comment": client.create_comment(number, text)}, status_code=201)
|
||||
except GiteaError as e:
|
||||
return JSONResponse({"error": str(e)}, status_code=502)
|
||||
|
||||
|
||||
@router.post("/api/suggestions/upload")
|
||||
async def upload(request: Request, file: UploadFile = File(...)):
|
||||
if current_user() is None:
|
||||
return JSONResponse({"error": "unauthorized"}, status_code=401)
|
||||
data = await file.read()
|
||||
if len(data) > MAX_UPLOAD_BYTES:
|
||||
return JSONResponse({"error": "too_large"}, status_code=413)
|
||||
if sniff_image(data) not in ALLOWED_IMAGE_TYPES:
|
||||
return JSONResponse({"error": "unsupported_type"}, status_code=415)
|
||||
origin = str(request.base_url)
|
||||
url = save_upload(file.filename or "image", data, UPLOAD_DIR, origin)
|
||||
return JSONResponse({"url": url}, status_code=201)
|
||||
Reference in New Issue
Block a user