49 lines
1.5 KiB
Python
49 lines
1.5 KiB
Python
"""Review business logic."""
|
||
from sqlalchemy.exc import IntegrityError
|
||
from app.extensions import db
|
||
from app.models.review import Review
|
||
|
||
|
||
class ReviewError(ValueError):
|
||
pass
|
||
|
||
|
||
def create_review(listing, author, rating: int, body: str | None = None):
|
||
"""Leave a review for a seller. Listing must be sold. Returns Review."""
|
||
from app.models.enums import ListingStatus
|
||
if listing.status != ListingStatus.sold:
|
||
raise ReviewError("can only review sold listings")
|
||
if listing.user_id == author.id:
|
||
raise ReviewError("cannot review your own listing")
|
||
if rating not in range(1, 6):
|
||
raise ReviewError("rating must be 1–5")
|
||
|
||
review = Review(
|
||
listing_id=listing.id,
|
||
author_id=author.id,
|
||
seller_id=listing.user_id,
|
||
rating=rating,
|
||
body=(body or "").strip() or None,
|
||
)
|
||
db.session.add(review)
|
||
try:
|
||
db.session.commit()
|
||
except IntegrityError:
|
||
db.session.rollback()
|
||
raise ReviewError("you have already reviewed this listing")
|
||
return review
|
||
|
||
|
||
def seller_rating(user_id) -> dict:
|
||
"""Return avg rating and count for a seller."""
|
||
from app.extensions import db
|
||
result = (db.session.query(
|
||
db.func.round(db.func.avg(Review.rating), 1).label("avg"),
|
||
db.func.count(Review.id).label("count"))
|
||
.filter(Review.seller_id == user_id)
|
||
.first())
|
||
return {
|
||
"avg": float(result.avg) if result.avg else None,
|
||
"count": result.count or 0,
|
||
}
|