api / routers /comments.py
jamelloverz-sketch
PopCorn API v3.5 - Media metadata, people, images, open CORS
c18e004
Raw
History Blame Contribute Delete
5.69 kB
from fastapi import APIRouter, HTTPException, Request, Query
from pydantic import BaseModel
from typing import Optional
from database import fetch_one, fetch_all, execute
from auth import get_current_user
from routers.utils import progress_achievement, create_notification
router = APIRouter()
async def _resolve_user(request: Request) -> dict:
user_data = await get_current_user(request)
user = await fetch_one("SELECT * FROM users WHERE user_id = ?", [str(user_data["id"])])
if not user:
raise HTTPException(status_code=404, detail="User not found")
return user
class CreateCommentBody(BaseModel):
content: str
rating: Optional[int] = None
class FullCommentBody(BaseModel):
media_type: str
tmdb_id: int
content: str
rating: Optional[int] = None
class LikeAction(BaseModel):
action: str
class ReportBody(BaseModel):
reason: str
@router.post("/api/v1/movie/{tmdb_id}/comments")
async def add_movie_comment(tmdb_id: int, body: CreateCommentBody, request: Request):
user = await _resolve_user(request)
await execute(
"INSERT INTO comments (user_id, tmdb_id, media_type, content, rating) VALUES (?, ?, 'movie', ?, ?)",
[str(user["id"]), str(tmdb_id), body.content, str(body.rating) if body.rating is not None else None],
)
return {"ok": True, "data": {"created": True}}
@router.get("/api/v1/movie/{tmdb_id}/comments")
async def get_movie_comments(tmdb_id: int, sort: str = Query("newest", pattern="^(newest|oldest|rating)$"), page: int = Query(1, ge=1)):
offset = (page - 1) * 20
order = "c.created_at DESC"
if sort == "oldest":
order = "c.created_at ASC"
elif sort == "rating":
order = "c.rating DESC, c.created_at DESC"
rows = await fetch_all(
f"""SELECT c.*, u.username, u.first_name, u.photo_url
FROM comments c
LEFT JOIN users u ON c.user_id = u.id
WHERE c.tmdb_id=? AND c.media_type='movie'
ORDER BY {order} LIMIT 20 OFFSET {offset}""",
[str(tmdb_id)],
)
total_row = await fetch_one("SELECT COUNT(*) as cnt FROM comments WHERE tmdb_id=? AND media_type='movie'", [str(tmdb_id)])
total = total_row["cnt"] if total_row else 0
return {
"ok": True,
"data": rows,
"meta": {"page": page, "total": total, "has_more": offset + 20 < total},
}
@router.post("/api/v1/series/{tmdb_id}/comments")
async def add_series_comment(tmdb_id: int, body: CreateCommentBody, request: Request):
user = await _resolve_user(request)
await execute(
"INSERT INTO comments (user_id, tmdb_id, media_type, content, rating) VALUES (?, ?, 'tv', ?, ?)",
[str(user["id"]), str(tmdb_id), body.content, str(body.rating) if body.rating is not None else None],
)
return {"ok": True, "data": {"created": True}}
@router.get("/api/v1/series/{tmdb_id}/comments")
async def get_series_comments(tmdb_id: int, sort: str = Query("newest", pattern="^(newest|oldest|rating)$"), page: int = Query(1, ge=1)):
offset = (page - 1) * 20
order = "c.created_at DESC"
if sort == "oldest":
order = "c.created_at ASC"
elif sort == "rating":
order = "c.rating DESC, c.created_at DESC"
rows = await fetch_all(
f"""SELECT c.*, u.username, u.first_name, u.photo_url
FROM comments c
LEFT JOIN users u ON c.user_id = u.id
WHERE c.tmdb_id=? AND c.media_type='tv'
ORDER BY {order} LIMIT 20 OFFSET {offset}""",
[str(tmdb_id)],
)
total_row = await fetch_one("SELECT COUNT(*) as cnt FROM comments WHERE tmdb_id=? AND media_type='tv'", [str(tmdb_id)])
total = total_row["cnt"] if total_row else 0
return {
"ok": True,
"data": rows,
"meta": {"page": page, "total": total, "has_more": offset + 20 < total},
}
@router.post("/api/v1/comment")
async def create_comment(body: FullCommentBody, request: Request):
user = await _resolve_user(request)
await execute(
"INSERT INTO comments (user_id, tmdb_id, media_type, content, rating) VALUES (?, ?, ?, ?, ?)",
[str(user["id"]), str(body.tmdb_id), body.media_type, body.content, str(body.rating) if body.rating is not None else None],
)
return {"ok": True, "data": {"created": True}}
@router.post("/api/v1/comment/{comment_id}/like")
async def like_comment(comment_id: int, body: LikeAction, request: Request):
user = await _resolve_user(request)
if body.action == "like":
await execute(
"INSERT OR IGNORE INTO comment_likes (comment_id, user_id) VALUES (?, ?)",
[str(comment_id), str(user["id"])],
)
elif body.action == "unlike":
await execute(
"DELETE FROM comment_likes WHERE comment_id=? AND user_id=?",
[str(comment_id), str(user["id"])],
)
return {"ok": True, "data": {"liked": body.action == "like"}}
@router.post("/api/v1/comment/{comment_id}/report")
async def report_comment(comment_id: int, body: ReportBody, request: Request):
user = await _resolve_user(request)
await execute(
"INSERT INTO comment_reports (comment_id, user_id, reason) VALUES (?, ?, ?)",
[str(comment_id), str(user["id"]), body.reason],
)
return {"ok": True, "data": {"reported": True}}
@router.post("/api/v1/rating/{rating_id}/helpful")
async def mark_rating_helpful(rating_id: int, request: Request):
user = await _resolve_user(request)
await execute(
"INSERT OR IGNORE INTO rating_helpful (rating_id, user_id) VALUES (?, ?)",
[str(rating_id), str(user["id"])],
)
return {"ok": True, "data": {"helpful": True}}