diff --git a/account/decorators.py b/account/decorators.py index f47c4a03..b3523664 100644 --- a/account/decorators.py +++ b/account/decorators.py @@ -92,7 +92,8 @@ def check_contest_permission(func): if not user.is_authenticated(): return self.error("Please login in first.") # password error - if ("contests" not in request.session) or (self.contest.id not in request.session["contests"]): + if ("accessible_contests" not in request.session) or \ + (self.contest.id not in request.session["accessible_contests"]): return self.error("Password is required.") return func(*args, **kwargs) diff --git a/contest/models.py b/contest/models.py index 42519988..eb1c88a8 100644 --- a/contest/models.py +++ b/contest/models.py @@ -45,6 +45,14 @@ class Contest(models.Model): def is_contest_admin(self, user): return user.is_authenticated() and (self.created_by == user or user.admin_type == AdminType.SUPER_ADMIN) + def check_oi_permission(self, user): + if self.status != ContestStatus.CONTEST_ENDED and self.real_time_rank == False: + if self.is_contest_admin(user): + return True + else: + return False + return True + class Meta: db_table = "contest" ordering = ("-create_time",) diff --git a/contest/views/oj.py b/contest/views/oj.py index 6811ef61..1e787ce2 100644 --- a/contest/views/oj.py +++ b/contest/views/oj.py @@ -67,7 +67,7 @@ class ContestPasswordVerifyAPI(APIView): # password verify OK. if "accessible_contests" not in request.session: request.session["accessible_contests"] = [] - request.session["contests"].append(contest.id) + request.session["accessible_contests"].append(contest.id) # https://docs.djangoproject.com/en/dev/topics/http/sessions/#when-sessions-are-saved request.session.modified = True return self.success(True) @@ -93,10 +93,12 @@ class ContestRankAPI(APIView): @check_contest_permission def get(self, request): - if self.contest.rule_type == ContestRuleType.ACM: - serializer = ACMContestRankSerializer - else: + if self.contest.rule_type == ContestRuleType.OI: + if not self.contest.check_oi_permission(request.user): + return self.error("You have no permission for ranks now") serializer = OIContestRankSerializer + else: + serializer = ACMContestRankSerializer cache_key = f"{CacheKey.contest_rank_cache}:{self.contest.id}" qs = cache.get(cache_key) diff --git a/judge/dispatcher.py b/judge/dispatcher.py index e457b29c..829a43d7 100644 --- a/judge/dispatcher.py +++ b/judge/dispatcher.py @@ -156,7 +156,6 @@ class JudgeDispatcher(object): with transaction.atomic(): # prepare problem and user_profile problem = Problem.objects.select_for_update().get(contest_id=self.contest_id, id=self.problem.id) - problem_info = problem.statistic_info user = User.objects.select_for_update().select_for_update("userprofile").get(id=self.submission.user_id) user_profile = user.userprofile if self.contest_id: @@ -165,25 +164,25 @@ class JudgeDispatcher(object): key = "problems" acm_problems_status = user_profile.acm_problems_status.get(key, {}) oi_problems_status = user_profile.oi_problems_status.get(key, {}) + problem_id = str(self.problem.id) + problem_info = problem.statistic_info + + # update problem info + result = str(self.submission.result) + problem_info[result] = problem_info.get(result, 0) + 1 + problem.statistic_info = problem_info # 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 + # 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_id = str(self.problem.id) if self.problem.rule_type == ProblemRuleType.ACM: - # update acm problem info - result = str(self.submission.result) - problem_info[result] = problem_info.get(result, 0) + 1 - problem.statistic_info = problem_info - # update user_profile if problem_id not in acm_problems_status: acm_problems_status[problem_id] = {"status": self.submission.result, "_id": self.problem._id} @@ -193,12 +192,8 @@ class JudgeDispatcher(object): user_profile.acm_problems_status[key] = acm_problems_status else: - # update oi problem info - score = self.submission.statistic_info["score"] - problem_info[score] = problem_info.get(score, 0) + 1 - problem.statistic_info = problem_info - # update user_profile + score = self.submission.statistic_info["score"] if problem_id not in oi_problems_status: user_profile.add_score(score) oi_problems_status[problem_id] = {"status": self.submission.result, @@ -218,8 +213,8 @@ class JudgeDispatcher(object): 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(CacheKey.contest_rank_cache + str(self.contest_id)) + if self.contest.rule_type == ContestRuleType.OI or self.contest.real_time_rank: + cache.delete(f"{CacheKey.contest_rank_cache}:{self.contest.id}") with transaction.atomic(): if self.contest.rule_type == ContestRuleType.ACM: acm_rank, _ = ACMContestRank.objects.select_for_update(). \ diff --git a/problem/serializers.py b/problem/serializers.py index 4856b6d6..0e44710b 100644 --- a/problem/serializers.py +++ b/problem/serializers.py @@ -95,6 +95,7 @@ class ProblemAdminSerializer(BaseProblemSerializer): class ContestProblemAdminSerializer(BaseProblemSerializer): class Meta: model = Problem + fields = "__all__" class ProblemSerializer(BaseProblemSerializer): diff --git a/problem/views/oj.py b/problem/views/oj.py index 321b1bb9..3410ae1c 100644 --- a/problem/views/oj.py +++ b/problem/views/oj.py @@ -21,11 +21,10 @@ class ProblemAPI(APIView): oi_problems_status = profile.oi_problems_status.get("problems", {}) # paginate data results = queryset_values.get("results") - if 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") @@ -53,11 +52,7 @@ class ProblemAPI(APIView): # 按照标签筛选 tag_text = request.GET.get("tag") if tag_text: - try: - tag = ProblemTag.objects.get(name=tag_text) - except ProblemTag.DoesNotExist: - return self.error("The Tag does not exist.") - problems = tag.problem_set.all().filter(visible=True) + problems = problems.filter(tags__name=tag_text) # 搜索的情况 keyword = request.GET.get("keyword", "").strip() @@ -76,7 +71,11 @@ class ProblemAPI(APIView): class ContestProblemAPI(APIView): def _add_problem_status(self, request, queryset_values): - if request.user.is_authenticated() and self.contest.rule_type != ContestRuleType.OI: + print("checking") + if self.contest.rule_type == ContestRuleType.OI and not self.contest.check_oi_permission(request.user): + return + print('here') + 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", {}) @@ -96,7 +95,7 @@ class ContestProblemAPI(APIView): except Problem.DoesNotExist: return self.error("Problem does not exist.") problem_data = ContestProblemSerializer(problem).data - self._add_problem_status(request, problem_data) + self._add_problem_status(request, [problem_data,]) return self.success(problem_data) contest_problems = Problem.objects.select_related("created_by").filter(contest=self.contest, visible=True) diff --git a/submission/views/oj.py b/submission/views/oj.py index c4bfe21b..4cf6a8c4 100644 --- a/submission/views/oj.py +++ b/submission/views/oj.py @@ -84,14 +84,13 @@ class SubmissionAPI(APIView): @login_required def put(self, request): try: - submission = Submission.objects.select_related("problem")\ - .get(id=request.data["id"], contest__isnull=True) + submission = Submission.objects.select_related("problem").get(id=request.data["id"]) except Submission.DoesNotExist: return self.error("Submission doesn't exist") if not submission.check_user_permission(request.user, check_share=False): return self.error("No permission to share the submission") if submission.contest and submission.contest.status == ContestStatus.CONTEST_UNDERWAY: - return self.error("Can not share submission during a contest going") + return self.error("Can not share submission now") submission.shared = request.data["shared"] submission.save(update_fields=["shared"]) return self.success() @@ -130,7 +129,7 @@ class ContestSubmissionListAPI(APIView): return self.error("Limit is needed") contest = self.contest - if contest.rule_type == ContestRuleType.OI and not contest.is_contest_admin(request.user): + if not contest.check_oi_permission(request.user): return self.error("No permission for OI contest submissions") submissions = Submission.objects.filter(contest_id=contest.id).select_related("problem__created_by") @@ -154,9 +153,11 @@ class ContestSubmissionListAPI(APIView): submissions = submissions.filter(create_time__gte=contest.start_time) # 封榜的时候只能看到自己的提交 - if not contest.real_time_rank and not contest.is_contest_admin(request.user): - submissions = submissions.filter(user_id=request.user.id) + if contest.rule_type == ContestRuleType.ACM: + if not contest.real_time_rank and not contest.is_contest_admin(request.user): + submissions = submissions.filter(user_id=request.user.id) data = self.paginate_data(request, submissions) data["results"] = SubmissionListSerializer(data["results"], many=True, user=request.user).data return self.success(data) + diff --git a/utils/constants.py b/utils/constants.py index be7057a6..390d5685 100644 --- a/utils/constants.py +++ b/utils/constants.py @@ -23,6 +23,6 @@ class ContestRuleType(Choices): class CacheKey: waiting_queue = "waiting_queue" - contest_rank_cache = "contest_rank_cache_" + contest_rank_cache = "contest_rank_cache" website_config = "website_config" option = "option"