""" CRUD для осей (ScaleDimension) и расшифровок вариантов ответов (ChoiceScore). Эндпоинты: POST /polls/{poll_id}/dimensions — создать ось для теста GET /polls/{poll_id}/dimensions — список осей теста PUT /dimensions/{dimension_id} — изменить ось DELETE /dimensions/{dimension_id} — удалить ось POST /dimensions/{dimension_id}/scores — задать расшифровку для варианта ответа GET /dimensions/{dimension_id}/scores — список расшифровок по оси GET /choices/{choice_id}/scores — расшифровки конкретного варианта DELETE /choice-scores/{score_id} — удалить расшифровку """ import uuid from typing import List, Optional from fastapi import APIRouter, HTTPException from pydantic import BaseModel from bd import get_session from bd.tables.poll import Poll from bd.tables.choice import Choice from bd.tables.scale import ScaleDimension, ChoiceScore router = APIRouter(tags=["scale"]) # --------------------------------------------------------------------------- # Схемы # --------------------------------------------------------------------------- class DimensionIn(BaseModel): name: str description: Optional[str] = None color: Optional[str] = None position: Optional[int] = None class DimensionOut(BaseModel): id: str poll_id: str name: str description: Optional[str] color: Optional[str] position: Optional[int] class ChoiceScoreIn(BaseModel): choice_id: str score: float = 1.0 class ChoiceScoreOut(BaseModel): id: str choice_id: str dimension_id: str score: float # --------------------------------------------------------------------------- # Оси (ScaleDimension) # --------------------------------------------------------------------------- @router.post("/polls/{poll_id}/dimensions", response_model=DimensionOut, status_code=201, tags=["scale"]) def create_dimension(poll_id: str, payload: DimensionIn): Session = get_session() try: pid = uuid.UUID(poll_id) except Exception: raise HTTPException(status_code=400, detail="Invalid poll UUID") with Session() as session: if not session.get(Poll, pid): raise HTTPException(status_code=404, detail="Poll not found") dim = ScaleDimension( poll_id=pid, name=payload.name, description=payload.description, color=payload.color, position=payload.position, ) session.add(dim) session.commit() session.refresh(dim) return DimensionOut( id=str(dim.id), poll_id=str(dim.poll_id), name=dim.name, description=dim.description, color=dim.color, position=dim.position, ) @router.get("/polls/{poll_id}/dimensions", response_model=List[DimensionOut], tags=["scale"]) def list_dimensions(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: dims = ( session.query(ScaleDimension) .filter(ScaleDimension.poll_id == pid) .order_by(ScaleDimension.position.asc().nullslast()) .all() ) return [ DimensionOut(id=str(d.id), poll_id=str(d.poll_id), name=d.name, description=d.description, color=d.color, position=d.position) for d in dims ] @router.put("/dimensions/{dimension_id}", response_model=DimensionOut, tags=["scale"]) def update_dimension(dimension_id: str, payload: DimensionIn): Session = get_session() try: did = uuid.UUID(dimension_id) except Exception: raise HTTPException(status_code=400, detail="Invalid dimension UUID") with Session() as session: dim = session.get(ScaleDimension, did) if not dim: raise HTTPException(status_code=404, detail="Dimension not found") dim.name = payload.name dim.description = payload.description dim.color = payload.color dim.position = payload.position session.commit() session.refresh(dim) return DimensionOut(id=str(dim.id), poll_id=str(dim.poll_id), name=dim.name, description=dim.description, color=dim.color, position=dim.position) @router.delete("/dimensions/{dimension_id}", status_code=204, tags=["scale"]) def delete_dimension(dimension_id: str): Session = get_session() try: did = uuid.UUID(dimension_id) except Exception: raise HTTPException(status_code=400, detail="Invalid dimension UUID") with Session() as session: dim = session.get(ScaleDimension, did) if not dim: raise HTTPException(status_code=404, detail="Dimension not found") session.delete(dim) session.commit() # --------------------------------------------------------------------------- # Расшифровки вариантов ответов (ChoiceScore) # --------------------------------------------------------------------------- @router.post("/dimensions/{dimension_id}/scores", response_model=ChoiceScoreOut, status_code=201, tags=["scale"]) def create_choice_score(dimension_id: str, payload: ChoiceScoreIn): Session = get_session() try: did = uuid.UUID(dimension_id) cid = uuid.UUID(payload.choice_id) except Exception: raise HTTPException(status_code=400, detail="Invalid UUID") with Session() as session: if not session.get(ScaleDimension, did): raise HTTPException(status_code=404, detail="Dimension not found") if not session.get(Choice, cid): raise HTTPException(status_code=404, detail="Choice not found") cs = ChoiceScore(choice_id=cid, dimension_id=did, score=payload.score) session.add(cs) session.commit() session.refresh(cs) return ChoiceScoreOut(id=str(cs.id), choice_id=str(cs.choice_id), dimension_id=str(cs.dimension_id), score=cs.score) @router.get("/dimensions/{dimension_id}/scores", response_model=List[ChoiceScoreOut], tags=["scale"]) def list_scores_by_dimension(dimension_id: str): Session = get_session() try: did = uuid.UUID(dimension_id) except Exception: raise HTTPException(status_code=400, detail="Invalid dimension UUID") with Session() as session: rows = session.query(ChoiceScore).filter(ChoiceScore.dimension_id == did).all() return [ChoiceScoreOut(id=str(r.id), choice_id=str(r.choice_id), dimension_id=str(r.dimension_id), score=r.score) for r in rows] @router.get("/choices/{choice_id}/scores", response_model=List[ChoiceScoreOut], tags=["scale"]) def list_scores_by_choice(choice_id: str): Session = get_session() try: cid = uuid.UUID(choice_id) except Exception: raise HTTPException(status_code=400, detail="Invalid choice UUID") with Session() as session: rows = session.query(ChoiceScore).filter(ChoiceScore.choice_id == cid).all() return [ChoiceScoreOut(id=str(r.id), choice_id=str(r.choice_id), dimension_id=str(r.dimension_id), score=r.score) for r in rows] @router.delete("/choice-scores/{score_id}", status_code=204, tags=["scale"]) def delete_choice_score(score_id: str): Session = get_session() try: sid = uuid.UUID(score_id) except Exception: raise HTTPException(status_code=400, detail="Invalid UUID") with Session() as session: cs = session.get(ChoiceScore, sid) if not cs: raise HTTPException(status_code=404, detail="Score not found") session.delete(cs) session.commit()