81 lines
2.5 KiB
Python
81 lines
2.5 KiB
Python
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
|
from sqlalchemy import func, select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.core.deps import get_current_active_user, get_db
|
|
from app.models.rating import Rating
|
|
from app.models.spot import Spot
|
|
from app.models.user import User
|
|
from app.schemas.common import PageResponse
|
|
from app.schemas.rating import RatingCreate, RatingOut
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.post("/spots/{spot_id}/rate", response_model=RatingOut)
|
|
async def rate_spot(
|
|
spot_id: int,
|
|
payload: RatingCreate,
|
|
current_user: User = Depends(get_current_active_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
result = await db.execute(select(Spot).where(Spot.id == spot_id))
|
|
spot = result.scalar_one_or_none()
|
|
if not spot:
|
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Spot not found")
|
|
|
|
existing = await db.execute(
|
|
select(Rating).where(Rating.user_id == current_user.id, Rating.spot_id == spot_id)
|
|
)
|
|
rating = existing.scalar_one_or_none()
|
|
|
|
if rating:
|
|
rating.score = payload.score
|
|
rating.short_comment = payload.short_comment
|
|
else:
|
|
rating = Rating(
|
|
spot_id=spot_id,
|
|
user_id=current_user.id,
|
|
score=payload.score,
|
|
short_comment=payload.short_comment,
|
|
)
|
|
db.add(rating)
|
|
|
|
await db.flush()
|
|
|
|
agg = await db.execute(
|
|
select(func.avg(Rating.score), func.count(Rating.id)).where(Rating.spot_id == spot_id)
|
|
)
|
|
avg_score, count = agg.one()
|
|
spot.avg_rating = round(float(avg_score), 2) if avg_score else None
|
|
spot.rating_count = count or 0
|
|
|
|
await db.commit()
|
|
await db.refresh(rating)
|
|
return rating
|
|
|
|
|
|
@router.get("/spots/{spot_id}/ratings", response_model=PageResponse[RatingOut])
|
|
async def list_ratings(
|
|
spot_id: int,
|
|
page: int = Query(default=1, ge=1),
|
|
page_size: int = Query(default=20, ge=1, le=100),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
count_result = await db.execute(
|
|
select(func.count(Rating.id)).where(Rating.spot_id == spot_id)
|
|
)
|
|
total = count_result.scalar() or 0
|
|
|
|
offset = (page - 1) * page_size
|
|
result = await db.execute(
|
|
select(Rating)
|
|
.where(Rating.spot_id == spot_id)
|
|
.order_by(Rating.created_at.desc())
|
|
.offset(offset)
|
|
.limit(page_size)
|
|
)
|
|
ratings = result.scalars().all()
|
|
|
|
return PageResponse(total=total, items=[RatingOut.model_validate(r) for r in ratings])
|