Spaces:
Runtime error
Runtime error
| 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 | |
| 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}} | |
| 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}, | |
| } | |
| 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}} | |
| 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}, | |
| } | |
| 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}} | |
| 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"}} | |
| 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}} | |
| 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}} | |