# retoor <retoor@molodetz.nl>
import logging
from typing import Annotated
from datetime import datetime, timezone
from fastapi import APIRouter, Request, Form
from fastapi.responses import RedirectResponse, JSONResponse
from devplacepy.database import get_table, db
from devplacepy.utils import generate_uid, require_user
from devplacepy.models import ReactionForm
logger = logging.getLogger(__name__)
router = APIRouter()
REACTABLE: set[str] = {"post", "comment", "gist", "project"}
@router.post("/{target_type}/{target_uid}")
async def react(request: Request, target_type: str, target_uid: str, data: Annotated[ReactionForm, Form()]):
user = require_user(request)
if target_type not in REACTABLE:
return JSONResponse({"error": "Invalid target"}, status_code=400)
emoji = data.emoji
reactions = get_table("reactions")
existing = reactions.find_one(user_uid=user["uid"], target_uid=target_uid, target_type=target_type, emoji=emoji)
if existing:
reactions.delete(id=existing["id"])
else:
reactions.insert({
"uid": generate_uid(),
"user_uid": user["uid"],
"target_uid": target_uid,
"target_type": target_type,
"emoji": emoji,
"created_at": datetime.now(timezone.utc).isoformat(),
})
counts = {row["emoji"]: row["c"] for row in db.query(
"SELECT emoji, COUNT(*) as c FROM reactions WHERE target_type=:tt AND target_uid=:tu GROUP BY emoji",
tt=target_type, tu=target_uid,
)}
mine = [row["emoji"] for row in reactions.find(user_uid=user["uid"], target_uid=target_uid, target_type=target_type)]
if request.headers.get("x-requested-with") == "fetch":
return JSONResponse({"counts": counts, "mine": mine})
return RedirectResponse(url=request.headers.get("Referer", "/feed"), status_code=302)