# retoor import logging from typing import Annotated from datetime import datetime, timezone from fastapi import Depends, APIRouter, Request from fastapi.responses import RedirectResponse, JSONResponse from devplacepy.database import get_table, db, _now_iso from devplacepy.utils import generate_uid, require_user, track_action, redirect_back from devplacepy.models import ReactionForm from devplacepy.services.audit import record as audit from devplacepy.dependencies import json_or_form 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, Depends(json_or_form(ReactionForm))], ): 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 and existing.get("deleted_at"): reactions.update( {"id": existing["id"], "deleted_at": None, "deleted_by": None}, ["id"] ) added = True elif existing: reactions.update( {"id": existing["id"], "deleted_at": _now_iso(), "deleted_by": user["uid"]}, ["id"], ) added = False 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(), "deleted_at": None, "deleted_by": None, } ) added = True reaction_event = "reaction.add" if added else "reaction.remove" if added: track_action(user["uid"], "reaction") audit.record( request, reaction_event, user=user, target_type=target_type, target_uid=target_uid, metadata={"emoji": emoji}, summary=f"{user['username']} {'added' if added else 'removed'} {emoji} on {target_type} {target_uid}", links=[audit.target(target_type, target_uid)], ) 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 AND deleted_at IS NULL 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, deleted_at=None, ) ] if request.headers.get("x-requested-with") == "fetch": return JSONResponse({"counts": counts, "mine": mine}) return RedirectResponse(url=redirect_back(request), status_code=302)