From 2a91fd5e9fe315928d362fdb8b2b67d70a97ccef Mon Sep 17 00:00:00 2001 From: zema1 Date: Fri, 29 Sep 2017 21:58:20 +0800 Subject: [PATCH] fix bugs due to problem id --- account/tests.py | 2 +- account/views/oj.py | 2 +- conf/tests.py | 7 ++++++- judge/dispatcher.py | 21 +++++++++++++-------- problem/views/oj.py | 13 +++++++------ submission/serializers.py | 2 ++ submission/tests.py | 2 +- submission/views/oj.py | 30 +++++++++++++++++++++++------- 8 files changed, 54 insertions(+), 25 deletions(-) diff --git a/account/tests.py b/account/tests.py index edf25b8a..7331a0ee 100644 --- a/account/tests.py +++ b/account/tests.py @@ -226,7 +226,7 @@ class UserProfileAPITest(APITestCase): def test_get_profile_without_login(self): resp = self.client.get(self.url) - self.assertDictEqual(resp.data, {"error": None, "data": 0}) + self.assertDictEqual(resp.data, {"error": None, "data": {}}) def test_get_profile(self): self.create_user("test", "test123") diff --git a/account/views/oj.py b/account/views/oj.py index 5b74ca88..cfb94726 100644 --- a/account/views/oj.py +++ b/account/views/oj.py @@ -39,7 +39,7 @@ class UserProfileAPI(APIView): """ user = request.user if not user.is_authenticated(): - return self.success(0) + return self.success({}) username = request.GET.get("username") try: if username: diff --git a/conf/tests.py b/conf/tests.py index ae9ee154..1694c218 100644 --- a/conf/tests.py +++ b/conf/tests.py @@ -3,6 +3,8 @@ import hashlib from django.utils import timezone from utils.api.tests import APITestCase +from utils.cache import default_cache +from utils.constants import CacheKey from .models import JudgeServer, JudgeServerToken, SMTPConfig @@ -76,7 +78,10 @@ class WebsiteConfigAPITest(APITestCase): url = self.reverse("website_info_api") resp = self.client.get(url) self.assertSuccess(resp) - self.assertEqual(resp.data["data"]["name_shortcut"], "test oj") + self.assertEqual(resp.data["data"]["name_shortcut"], "oj") + + def tearDown(self): + default_cache.delete(CacheKey.website_config) class JudgeServerHeartbeatTest(APITestCase): diff --git a/judge/dispatcher.py b/judge/dispatcher.py index 1488621f..8ab66885 100644 --- a/judge/dispatcher.py +++ b/judge/dispatcher.py @@ -4,17 +4,16 @@ import logging from urllib.parse import urljoin import requests -from django.core.cache import cache from django.db import transaction from django.db.models import F from account.models import User from conf.models import JudgeServer, JudgeServerToken -from contest.models import ContestRuleType, ACMContestRank, OIContestRank +from contest.models import ContestRuleType, ACMContestRank, OIContestRank, ContestStatus from judge.languages import languages from problem.models import Problem, ProblemRuleType from submission.models import JudgeStatus, Submission -from utils.cache import judge_cache +from utils.cache import judge_cache, default_cache from utils.constants import CacheKey logger = logging.getLogger(__name__) @@ -126,6 +125,7 @@ class JudgeDispatcher(object): if resp["err"]: self.submission.result = JudgeStatus.COMPILE_ERROR self.submission.statistic_info["err_info"] = resp["data"] + self.submission.statistic_info["score"] = 0 else: self._compute_statistic_info(resp["data"]) error_test_case = list(filter(lambda case: case["result"] != 0, resp["data"])) @@ -154,6 +154,9 @@ class JudgeDispatcher(object): return self._request(urljoin(service_url, "compile_spj"), data=data) def update_problem_status(self): + if self.contest_id and self.contest.status != ContestStatus.CONTEST_UNDERWAY: + logger.info("Contest debug mode, id: " + str(self.contest_id) + ", submission id: " + self.submission.id) + return with transaction.atomic(): # prepare problem and user_profile problem = Problem.objects.select_for_update().get(contest_id=self.contest_id, id=self.problem.id) @@ -168,15 +171,15 @@ class JudgeDispatcher(object): oi_problems_status = user_profile.oi_problems_status.get(key, {}) # update submission and accepted number counter + problem.submission_number += 1 + if self.submission.result == JudgeStatus.ACCEPTED: + problem.accepted_number += 1 # only when submission is not in contest, we update user profile, # in other words, users' submission in a contest will not be counted in user profile if not self.contest_id: user_profile.submission_number += 1 if self.submission.result == JudgeStatus.ACCEPTED: user_profile.accepted_number += 1 - problem.submission_number += 1 - if self.submission.result == JudgeStatus.ACCEPTED: - problem.accepted_number += 1 problem_id = str(self.problem.id) if self.problem.rule_type == ProblemRuleType.ACM: @@ -217,8 +220,10 @@ class JudgeDispatcher(object): "submission_number", "accepted_number", "acm_problems_status", "oi_problems_status"]) def update_contest_rank(self): + if self.contest_id and self.contest.status != ContestStatus.CONTEST_UNDERWAY: + return if self.contest.real_time_rank: - cache.delete(str(self.contest.id) + "_rank_cache") + default_cache.delete(CacheKey.contest_rank_cache + str(self.contest_id)) with transaction.atomic(): if self.contest.rule_type == ContestRuleType.ACM: acm_rank, _ = ACMContestRank.objects.select_for_update(). \ @@ -232,7 +237,7 @@ class JudgeDispatcher(object): def _update_acm_contest_rank(self, rank): info = rank.submission_info.get(str(self.submission.problem_id)) # 因前面更改过,这里需要重新获取 - problem = Problem.objects.get(contest_id=self.contest_id, _id=self.problem.id) + problem = Problem.objects.get(contest_id=self.contest_id, id=self.problem.id) # 此题提交过 if info: if info["is_ac"]: diff --git a/problem/views/oj.py b/problem/views/oj.py index 6eb84675..f5b03f86 100644 --- a/problem/views/oj.py +++ b/problem/views/oj.py @@ -18,7 +18,8 @@ class ProblemAPI(APIView): problem_id = request.GET.get("problem_id") if problem_id: try: - problem = Problem.objects.select_related("created_by").get(_id=problem_id, visible=True) + problem = Problem.objects.select_related("created_by")\ + .get(_id=problem_id, contest_id__isnull=True, visible=True) return self.success(ProblemSerializer(problem).data) except Problem.DoesNotExist: return self.error("Problem does not exist") @@ -27,7 +28,7 @@ class ProblemAPI(APIView): if not limit: return self.error("Limit is needed") - problems = Problem.objects.select_related("created_by").filter(visible=True) + problems = Problem.objects.select_related("created_by").filter(contest_id__isnull=True, visible=True) # 按照标签筛选 tag_text = request.GET.get("tag") if tag_text: @@ -54,9 +55,9 @@ class ProblemAPI(APIView): oi_problems_status = profile.oi_problems_status.get("problems", {}) for problem in data["results"]: if problem["rule_type"] == ProblemRuleType.ACM: - problem["my_status"] = acm_problems_status.get(problem["_id"], None) + problem["my_status"] = acm_problems_status.get(str(problem["id"]), None) else: - problem["my_status"] = oi_problems_status.get(problem["_id"], None) + problem["my_status"] = oi_problems_status.get(str(problem["id"]), None) return self.success(data) @@ -83,5 +84,5 @@ class ContestProblemAPI(APIView): else: problems_status = profile.oi_problems_status.get("contest_problems", {}) for problem in data: - problem["my_status"] = problems_status.get(problem["_id"], None) - return self.success(ContestProblemSerializer(contest_problems, many=True).data) + problem["my_status"] = problems_status.get(str(problem["id"]), None) + return self.success(data) diff --git a/submission/serializers.py b/submission/serializers.py index 1c5493d1..ae8c3a60 100644 --- a/submission/serializers.py +++ b/submission/serializers.py @@ -20,6 +20,7 @@ class SubmissionModelSerializer(serializers.ModelSerializer): # 不显示submission info的serializer, 用于ACM rule_type class SubmissionSafeSerializer(serializers.ModelSerializer): + problem = serializers.SlugRelatedField(read_only=True, slug_field="_id") statistic_info = serializers.JSONField() class Meta: @@ -28,6 +29,7 @@ class SubmissionSafeSerializer(serializers.ModelSerializer): class SubmissionListSerializer(serializers.ModelSerializer): + problem = serializers.SlugRelatedField(read_only=True, slug_field="_id") statistic_info = serializers.JSONField() show_link = serializers.SerializerMethodField() diff --git a/submission/tests.py b/submission/tests.py index 4c474ba5..ca4ffa5c 100644 --- a/submission/tests.py +++ b/submission/tests.py @@ -16,7 +16,7 @@ DEFAULT_PROBLEM_DATA = {"_id": "110", "title": "test", "description": "

testtest

", "source": "test"} DEFAULT_SUBMISSION_DATA = { - "problem_id": "110", + "problem_id": "1", "user_id": 1, "username": "test", "code": "xxxxxxxxxxxxxx", diff --git a/submission/views/oj.py b/submission/views/oj.py index 11c76e9e..e2c59f27 100644 --- a/submission/views/oj.py +++ b/submission/views/oj.py @@ -1,3 +1,4 @@ +from account.models import AdminType from account.decorators import login_required, check_contest_permission from judge.tasks import judge_task # from judge.dispatcher import JudgeDispatcher @@ -25,7 +26,7 @@ def _submit(response, user, problem_id, language, code, contest_id): return response.error("Please wait %d seconds" % int(bucket.expected_time() + 1)) try: - problem = Problem.objects.get(_id=problem_id, + problem = Problem.objects.get(id=problem_id, contest_id=contest_id, visible=True) except Problem.DoesNotExist: @@ -53,15 +54,17 @@ class SubmissionAPI(APIView): contest = Contest.objects.get(id=data["contest_id"]) except Contest.DoesNotExist: return self.error("Contest doesn't exist.") - if contest.status != ContestStatus.CONTEST_UNDERWAY and request.user != contest.created_by: - return self.error("Contest have not started or have ended, you can't submit code.") + if contest.status == ContestStatus.CONTEST_ENDED: + return self.error("The contest have ended") + if contest.status == ContestStatus.CONTEST_NOT_START and request.user != contest.created_by: + return self.error("Contest have not started") return _submit(self, request.user, data["problem_id"], data["language"], data["code"], data.get("contest_id")) @login_required def get(self, request): submission_id = request.GET.get("id") if not submission_id: - return self.error("Parameter id doesn't exist.") + return self.error("Parameter id do esn't exist.") try: submission = Submission.objects.select_related("problem").get(id=submission_id) except Submission.DoesNotExist: @@ -86,8 +89,21 @@ class SubmissionListAPI(APIView): @check_contest_permission def _get_contest_submission_list(self, request): - subs = Submission.objects.filter(contest_id=self.contest.id) - return self.process_submissions(request, subs) + contest = self.contest + # todo OI mode + submissions = Submission.objects.filter(contest_id=contest.id) + # filter the test submissions submitted before contest start + if contest.status != ContestStatus.CONTEST_NOT_START: + print(contest.start_time) + submissions = submissions.filter(create_time__gte=contest.start_time) + + # 封榜的时候只能看到自己的提交 + if not contest.real_time_rank: + if request.user and not ( + request.user.admin_type == AdminType.SUPER_ADMIN or request.user == contest.created_by): + submissions = submissions.filter(user_id=request.user.id) + + return self.process_submissions(request, submissions) def process_submissions(self, request, submissions): problem_id = request.GET.get("problem_id") @@ -98,7 +114,7 @@ class SubmissionListAPI(APIView): problem = Problem.objects.get(_id=problem_id, visible=True) except Problem.DoesNotExist: return self.error("Problem doesn't exist") - submissions = problem.submission_set.all() + submissions = submissions.filter(problem=problem) if myself and myself == "1": submissions = submissions.filter(user_id=request.user.id) if result: