Files
api-copp/route/response_crud.py
2026-04-01 14:18:52 +05:00

161 lines
5.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
from typing import List, Optional
import uuid
from bd import make_engine
from bd.tables.poll import Poll
from bd.tables.question import Question
from bd.tables.response import Response, Answer
from bd.tables.scale import ScaleDimension
router = APIRouter(tags=["responses"], prefix="/polls")
class AnswerIn(BaseModel):
question_id: str
choice_id: Optional[str]
text: Optional[str]
class ResponseIn(BaseModel):
user_id: Optional[str] = None
group_id: Optional[str] = None
organization_id: Optional[str] = None
answers: List[AnswerIn]
def get_session():
from sqlalchemy.orm import sessionmaker
return sessionmaker(bind=make_engine(), future=True)
@router.post("/{poll_id}/responses", status_code=201)
def submit_response(poll_id: str, payload: ResponseIn):
Session = get_session()
try:
pid = uuid.UUID(poll_id)
except Exception:
raise HTTPException(status_code=400, detail="Invalid poll UUID")
with Session() as session:
poll = session.get(Poll, pid)
if not poll:
raise HTTPException(status_code=404, detail="Poll not found")
resp = Response(poll_id=pid)
if payload.user_id:
try:
resp.user_id = uuid.UUID(payload.user_id)
except Exception:
raise HTTPException(status_code=400, detail="Invalid user_id UUID")
if payload.group_id:
try:
resp.group_id = uuid.UUID(payload.group_id)
except Exception:
raise HTTPException(status_code=400, detail="Invalid group_id UUID")
if payload.organization_id:
try:
resp.organization_id = uuid.UUID(payload.organization_id)
except Exception:
raise HTTPException(status_code=400, detail="Invalid organization_id UUID")
session.add(resp)
# validate answers
for a in payload.answers:
try:
qid = uuid.UUID(a.question_id)
except Exception:
raise HTTPException(status_code=400, detail="Invalid question_id UUID")
question = session.get(Question, qid)
if not question or question.poll_id != pid:
raise HTTPException(status_code=400, detail="Question does not belong to poll")
choice_uuid = None
if a.choice_id:
try:
choice_uuid = uuid.UUID(a.choice_id)
except Exception:
raise HTTPException(status_code=400, detail="Invalid choice_id UUID")
answer = Answer(response=resp, question_id=qid, choice_id=choice_uuid, text=a.text)
session.add(answer)
session.commit()
session.refresh(resp)
# Автоматически считаем радарный результат, если у теста есть оси
has_dimensions = (
session.query(ScaleDimension)
.filter(ScaleDimension.poll_id == pid)
.first()
) is not None
radar_id: Optional[str] = None
if has_dimensions:
try:
from route.radar_crud import compute_radar
radar = compute_radar(resp.id, session)
radar_id = str(radar.id)
except Exception:
pass # не ломаем сдачу, если расчёт не удался
result: dict = {"id": str(resp.id)}
if radar_id:
result["radar_result_id"] = radar_id
return result
@router.get("/responses/")
def list_all_responses():
Session = get_session()
with Session() as session:
rows = session.query(Response).all()
return [
{"id": str(r.id), "poll_id": str(r.poll_id), "user_id": str(r.user_id) if r.user_id else None, "submitted_at": r.submitted_at.isoformat()}
for r in rows
]
@router.get("/{poll_id}/responses")
def list_responses(poll_id: str):
Session = get_session()
try:
pid = uuid.UUID(poll_id)
except Exception:
raise HTTPException(status_code=400, detail="Invalid poll UUID")
with Session() as session:
rows = session.query(Response).filter(Response.poll_id == pid).all()
return [{"id": str(r.id), "user_id": str(r.user_id) if r.user_id else None, "submitted_at": r.submitted_at.isoformat()} for r in rows]
@router.get("/responses/{response_id}")
def get_response(response_id: str):
Session = get_session()
try:
rid = uuid.UUID(response_id)
except Exception:
raise HTTPException(status_code=400, detail="Invalid UUID")
with Session() as session:
r = session.get(Response, rid)
if not r:
raise HTTPException(status_code=404, detail="Response not found")
return {
"id": str(r.id),
"poll_id": str(r.poll_id),
"user_id": str(r.user_id) if r.user_id else None,
"group_id": str(r.group_id) if r.group_id else None,
"organization_id": str(r.organization_id) if r.organization_id else None,
"submitted_at": r.submitted_at.isoformat(),
"answers": [
{"id": str(a.id), "question_id": str(a.question_id), "choice_id": str(a.choice_id) if a.choice_id else None, "text": a.text}
for a in r.answers
],
}
@router.get("/users/{user_id}/responses")
def list_responses_by_user(user_id: str):
Session = get_session()
try:
uid = uuid.UUID(user_id)
except Exception:
raise HTTPException(status_code=400, detail="Invalid user UUID")
with Session() as session:
rows = session.query(Response).filter(Response.user_id == uid).all()
return [{"id": str(r.id), "poll_id": str(r.poll_id), "submitted_at": r.submitted_at.isoformat()} for r in rows]