File size: 1,709 Bytes
2167c4f 038ad63 2167c4f 038ad63 2167c4f 038ad63 7dfd4df 038ad63 7dfd4df 2167c4f 038ad63 7dfd4df 2167c4f 038ad63 7dfd4df 2167c4f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | import json
import time
import re
from fastapi import APIRouter
from pydantic import BaseModel, ConfigDict, Field, field_validator
from src.config import get_settings
router = APIRouter()
class FeedbackRequest(BaseModel):
model_config = ConfigDict(extra="forbid")
request_id: str = Field(pattern=r"^[A-Za-z0-9_-]{8,80}$")
feedback: str
comment: str = Field(default="", max_length=500)
# The existing LibGuides client sends this field to its Worker. Accept it
# if forwarded, but do not store it in the local feedback fallback.
session_id: str | None = Field(default=None, pattern=r"^[A-Za-z0-9_-]{8,80}$")
@field_validator("feedback")
@classmethod
def valid_feedback(cls, v: str) -> str:
if v not in {"up", "down"}:
raise ValueError("feedback must be up or down")
return v
@router.post("")
async def save_feedback(req: FeedbackRequest):
settings = get_settings()
comment = re.sub(r"[\w.+-]+@[\w-]+\.[\w.-]+", "[email]", req.comment)
comment = re.sub(r"\b\d{6,}\b", "[number]", comment)
payload = {
"timestamp": time.time(),
"request_id": req.request_id,
"feedback": req.feedback,
"comment": comment[:500],
}
settings.feedback_path.parent.mkdir(parents=True, exist_ok=True)
with settings.feedback_path.open("a", encoding="utf-8") as handle:
handle.write(json.dumps(payload, ensure_ascii=False) + "\n")
try:
from app import metrics_service
metrics_service.incr("feedback_total")
metrics_service.incr_bucket("feedback_breakdown", req.feedback)
except Exception:
pass
return {"status": "ok"}
|