Skip to content

Commit

Permalink
Merge pull request #52 from idkbrowby/anand/rating-endpoints
Browse files Browse the repository at this point in the history
feat: make endpoint to create ratings
  • Loading branch information
vivekashok1221 authored Mar 24, 2024
2 parents 590e0d2 + 4eec279 commit b4639fa
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 12 deletions.
7 changes: 7 additions & 0 deletions src/backend/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import re
from datetime import datetime
from typing import Annotated

from pydantic import BaseModel, EmailStr, Field, validator

Expand All @@ -10,6 +11,12 @@
USERNAME_RE = re.compile("^[A-Za-z0-9_-]*$")


class PostRatingBody(BaseModel):
"""Represents a rating for a post. The rating should be an integer in the range [0,5]."""

rating: Annotated[int, Field(ge=0, le=5)]


class UserInLogin(BaseModel):
"""Model representing user at login."""

Expand Down
51 changes: 39 additions & 12 deletions src/backend/routers/post.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
from fastapi import APIRouter, Body, Depends, Form, Header, HTTPException, Query, UploadFile
from loguru import logger

from prisma.errors import PrismaError
from prisma.errors import ForeignKeyViolationError, PrismaError
from prisma.models import Post, PostComment, PostMedia, PostRating
from src.backend.dependencies import is_authorized
from src.backend.models import CreatePostResponse, MessageResponse, PostDetails
from src.backend.models import CreatePostResponse, MessageResponse, PostDetails, PostRatingBody
from src.backend.paginate_db import Page, paginate
from src.backend.storage import _upload_to_storage

Expand Down Expand Up @@ -73,6 +73,8 @@ async def create_post(
data=[{"post_id": inserted_post.id, "object_url": url} for url in urls]
)
response["urls"] = urls
else:
response["urls"] = []
return response


Expand All @@ -94,32 +96,36 @@ async def search_posts(
return Page(data=posts, count=len(posts), cursor_id=None)


@router.get("/{id}")
async def get_post(id: str) -> PostDetails:
@router.get("/{post_id}")
async def get_post(post_id: str) -> PostDetails:
"""Get full details of a specific post."""
post = await Post.prisma().find_first(
where={"id": id, "deleted": False}, include={"tags": True, "media": True, "author": True}
where={"id": post_id, "deleted": False},
include={"tags": True, "media": True, "author": True},
)
if not post:
raise HTTPException(404, "Post not found")
comments = await paginate(
PostComment,
page_size=20,
where={"post_id": id},
where={"post_id": post_id},
include={"author": True},
order={"created_at": "desc"},
)
avg_rating_query = await PostRating.prisma().group_by(
by=["post_id"], avg={"value": True}, having={"post_id": id}
by=["post_id"], avg={"value": True}, having={"post_id": post_id}
)
avg_rating = round(avg_rating_query[0]["_avg"]["value"]) # type: ignore
if len(avg_rating_query) > 0:
avg_rating = round(avg_rating_query[0]["_avg"]["value"]) # type: ignore
else:
avg_rating = 0
return PostDetails(post=post, comments=comments, avg_rating=avg_rating)


@router.delete("/{id}")
@router.delete("/{post_id}")
async def delete_post(
user_id: Annotated[UUID, Depends(is_authorized)],
id: str,
post_id: str,
) -> MessageResponse:
"""Delete a post."""
try:
Expand All @@ -128,7 +134,7 @@ async def delete_post(
# uniquely identify a row
# and we need to filter by author_id as well
deleted_post = await Post.prisma().update_many(
data={"deleted": True}, where={"id": id, "author_id": str(user_id)}
data={"deleted": True}, where={"id": post_id, "author_id": str(user_id)}
)
except PrismaError as e:
logger.warning(f"Could not delete post: {e}")
Expand All @@ -155,7 +161,7 @@ async def create_comment(
)
except PrismaError as e:
logger.warning(f"Could not create comment: {e}")
raise HTTPException(400, "Could not create the comment due to an internal error")
raise HTTPException(500, "Could not create the comment due to an internal error")
return comment


Expand All @@ -179,6 +185,27 @@ async def get_comments(
)


@router.post("/{post_id}/rating")
async def create_rating(
user_id: Annotated[UUID, Depends(is_authorized)], post_id: str, rating: PostRatingBody
) -> PostRating:
"""Create a rating on the specified post."""
try:
rating_record = await PostRating.prisma().upsert(
where={"post_id_author_id": {"post_id": post_id, "author_id": str(user_id)}},
data={
"create": {"post_id": post_id, "author_id": str(user_id), "value": rating.rating},
"update": {"value": rating.rating},
},
)
except ForeignKeyViolationError:
raise HTTPException(404, "Post not found")
except PrismaError as e:
logger.warning(f"Could not create rating: {e}")
raise HTTPException(500, "Could not create the rating due to an internal error")
return rating_record


@router.delete("/{post_id}/comments/{comment_id}")
async def delete_comment(
user_id: Annotated[UUID, Depends(is_authorized)],
Expand Down

0 comments on commit b4639fa

Please sign in to comment.