Files
OnlineJudge/problem/views/oj.py
2025-04-14 12:13:35 +08:00

182 lines
6.8 KiB
Python

from datetime import datetime
import random
from django.db.models import Q, Count
from account.models import User
from submission.models import Submission, JudgeStatus
from utils.api import APIView
from account.decorators import check_contest_permission
from ..models import ProblemTag, Problem, ProblemRuleType
from ..serializers import (
ProblemSerializer,
TagSerializer,
ProblemSafeSerializer,
ProblemListSerializer,
)
from contest.models import ContestRuleType
class ProblemTagAPI(APIView):
def get(self, request):
qs = ProblemTag.objects
keyword = request.GET.get("keyword")
if keyword:
qs = ProblemTag.objects.filter(name__icontains=keyword)
tags = qs.annotate(problem_count=Count("problem")).filter(problem_count__gt=0)
return self.success(TagSerializer(tags, many=True).data)
class PickOneAPI(APIView):
def get(self, request):
problems = Problem.objects.filter(contest_id__isnull=True, visible=True)
count = problems.count()
if count == 0:
return self.error("No problem to pick")
return self.success(problems[random.randint(0, count - 1)]._id)
class ProblemAPI(APIView):
@staticmethod
def _add_problem_status(request, queryset_values):
if request.user.is_authenticated:
profile = request.user.userprofile
acm_problems_status = profile.acm_problems_status.get("problems", {})
oi_problems_status = profile.oi_problems_status.get("problems", {})
# paginate data
results = queryset_values.get("results")
if results is not None:
problems = results
else:
problems = [
queryset_values,
]
for problem in problems:
if problem["rule_type"] == ProblemRuleType.ACM:
problem["my_status"] = acm_problems_status.get(
str(problem["id"]), {}
).get("status")
else:
problem["my_status"] = oi_problems_status.get(
str(problem["id"]), {}
).get("status")
def get(self, request):
# 问题详情页
problem_id = request.GET.get("problem_id")
if problem_id:
try:
problem = Problem.objects.select_related("created_by").get(
_id=problem_id, contest_id__isnull=True, visible=True
)
problem_data = ProblemSerializer(problem).data
self._add_problem_status(request, problem_data)
return self.success(problem_data)
except Problem.DoesNotExist:
return self.error("Problem does not exist")
limit = request.GET.get("limit")
if not limit:
return self.error("Limit is needed")
problems = (
Problem.objects.select_related("created_by")
.filter(contest_id__isnull=True, visible=True)
.order_by("-create_time")
)
# 按照标签筛选
tag_text = request.GET.get("tag")
if tag_text:
problems = problems.filter(tags__name=tag_text)
# 搜索的情况
keyword = request.GET.get("keyword", "").strip()
if keyword:
problems = problems.filter(
Q(title__icontains=keyword) | Q(_id__icontains=keyword)
)
# 难度筛选
difficulty = request.GET.get("difficulty")
if difficulty:
problems = problems.filter(difficulty=difficulty)
# 根据profile 为做过的题目添加标记
data = self.paginate_data(request, problems, ProblemListSerializer)
self._add_problem_status(request, data)
return self.success(data)
class ContestProblemAPI(APIView):
def _add_problem_status(self, request, queryset_values):
if request.user.is_authenticated:
profile = request.user.userprofile
if self.contest.rule_type == ContestRuleType.ACM:
problems_status = profile.acm_problems_status.get(
"contest_problems", {}
)
else:
problems_status = profile.oi_problems_status.get("contest_problems", {})
for problem in queryset_values:
problem["my_status"] = problems_status.get(str(problem["id"]), {}).get(
"status"
)
@check_contest_permission(check_type="problems")
def get(self, request):
problem_id = request.GET.get("problem_id")
if problem_id:
try:
problem = Problem.objects.select_related("created_by").get(
_id=problem_id, contest=self.contest, visible=True
)
except Problem.DoesNotExist:
return self.error("Problem does not exist.")
if self.contest.problem_details_permission(request.user):
problem_data = ProblemSerializer(problem).data
self._add_problem_status(
request,
[
problem_data,
],
)
else:
problem_data = ProblemSafeSerializer(problem).data
return self.success(problem_data)
contest_problems = Problem.objects.select_related("created_by").filter(
contest=self.contest, visible=True
)
if self.contest.problem_details_permission(request.user):
data = ProblemListSerializer(contest_problems, many=True).data
self._add_problem_status(request, data)
else:
data = ProblemSafeSerializer(contest_problems, many=True).data
return self.success(data)
class ProblemSolvedPeopleCount(APIView):
def get(self, request):
problem_id = request.GET.get("problem_id")
if not request.user.is_authenticated:
return self.success("0%")
submission_count = Submission.objects.filter(
user_id=request.user.id,
problem_id=problem_id,
result=JudgeStatus.ACCEPTED,
).count()
if submission_count == 0:
return self.success("0%")
today = datetime.today()
oneYearAge = datetime(today.year - 1, today.month, today.day, 0, 0)
total_count = User.objects.filter(
is_disabled=False, last_login__gte=oneYearAge
).count()
accepted_count = Submission.objects.filter(
problem_id=problem_id,
result=JudgeStatus.ACCEPTED,
create_time__gte=oneYearAge,
).aggregate(user_count=Count("user_id", distinct=True))["user_count"]
if accepted_count < total_count:
rate = "%.2f" % ((total_count - accepted_count) / total_count * 100)
else:
rate = "0"
return self.success(f"{rate}%")