from django.db.models import Avg, Count from django.db.models.functions import Round from account.decorators import login_required from comment.models import Comment from comment.serializers import CommentSerializer, CreateCommentSerializer from problem.models import Problem from submission.models import JudgeStatus, Submission from utils.api import AsyncAPIView from utils.api.api import validate_serializer from utils.async_helpers import async_cache_delete, async_cache_get, async_cache_set from utils.constants import CacheKey class CommentAPI(AsyncAPIView): @validate_serializer(CreateCommentSerializer) @login_required async def post(self, request): data = request.data try: problem = await Problem.objects.aget(id=data["problem_id"], visible=True) except Problem.DoesNotExist: return self.error("problem is not exists") submission = await ( Submission.objects.select_related("problem") .filter( user_id=request.user.id, problem_id=data["problem_id"], result__in=[JudgeStatus.ACCEPTED, JudgeStatus.AST_CHECK_FAILED], ) .afirst() ) if not submission: return self.error("submission is not exists or not accepted") language = submission.language if language == "Python3": language = "Python" await Comment.objects.acreate( user=request.user, problem=problem, submission=submission, language=language, description_rating=data["description_rating"], difficulty_rating=data["difficulty_rating"], comprehensive_rating=data["comprehensive_rating"], content=data["content"], ) await async_cache_delete(f"{CacheKey.comment_stats}:{problem.id}") return self.success() @login_required async def get(self, request): problem_id = request.GET.get("problem_id") comment = await ( Comment.objects.select_related("problem") .filter(user=request.user, problem_id=problem_id) .afirst() ) if comment: return self.success(await self.async_serialize_data(CommentSerializer, comment)) else: return self.success() class CommentStatisticsAPI(AsyncAPIView): async def get(self, request): problem_id = request.GET.get("problem_id") cache_key = f"{CacheKey.comment_stats}:{problem_id}" cached = await async_cache_get(cache_key) if cached is not None: return self.success(cached) agg = await Comment.objects.filter(problem_id=problem_id).aaggregate( count=Count("id"), description=Round(Avg("description_rating"), 2), difficulty=Round(Avg("difficulty_rating"), 2), comprehensive=Round(Avg("comprehensive_rating"), 2), ) if not agg["count"]: return self.success() data = {"count": agg["count"], "rating": { "description": agg["description"], "difficulty": agg["difficulty"], "comprehensive": agg["comprehensive"], }} await async_cache_set(cache_key, data, 3600) return self.success(data)