完善OI细则

This commit is contained in:
zema1 2017-10-16 09:45:29 +08:00
parent 2c5a1e42bf
commit f5566148bc
8 changed files with 44 additions and 37 deletions

View File

@ -92,7 +92,8 @@ def check_contest_permission(func):
if not user.is_authenticated(): if not user.is_authenticated():
return self.error("Please login in first.") return self.error("Please login in first.")
# password error # 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 self.error("Password is required.")
return func(*args, **kwargs) return func(*args, **kwargs)

View File

@ -45,6 +45,14 @@ class Contest(models.Model):
def is_contest_admin(self, user): def is_contest_admin(self, user):
return user.is_authenticated() and (self.created_by == user or user.admin_type == AdminType.SUPER_ADMIN) 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: class Meta:
db_table = "contest" db_table = "contest"
ordering = ("-create_time",) ordering = ("-create_time",)

View File

@ -67,7 +67,7 @@ class ContestPasswordVerifyAPI(APIView):
# password verify OK. # password verify OK.
if "accessible_contests" not in request.session: if "accessible_contests" not in request.session:
request.session["accessible_contests"] = [] 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 # https://docs.djangoproject.com/en/dev/topics/http/sessions/#when-sessions-are-saved
request.session.modified = True request.session.modified = True
return self.success(True) return self.success(True)
@ -93,10 +93,12 @@ class ContestRankAPI(APIView):
@check_contest_permission @check_contest_permission
def get(self, request): def get(self, request):
if self.contest.rule_type == ContestRuleType.ACM: if self.contest.rule_type == ContestRuleType.OI:
serializer = ACMContestRankSerializer if not self.contest.check_oi_permission(request.user):
else: return self.error("You have no permission for ranks now")
serializer = OIContestRankSerializer serializer = OIContestRankSerializer
else:
serializer = ACMContestRankSerializer
cache_key = f"{CacheKey.contest_rank_cache}:{self.contest.id}" cache_key = f"{CacheKey.contest_rank_cache}:{self.contest.id}"
qs = cache.get(cache_key) qs = cache.get(cache_key)

View File

@ -156,7 +156,6 @@ class JudgeDispatcher(object):
with transaction.atomic(): with transaction.atomic():
# prepare problem and user_profile # prepare problem and user_profile
problem = Problem.objects.select_for_update().get(contest_id=self.contest_id, id=self.problem.id) 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 = User.objects.select_for_update().select_for_update("userprofile").get(id=self.submission.user_id)
user_profile = user.userprofile user_profile = user.userprofile
if self.contest_id: if self.contest_id:
@ -165,25 +164,25 @@ class JudgeDispatcher(object):
key = "problems" key = "problems"
acm_problems_status = user_profile.acm_problems_status.get(key, {}) acm_problems_status = user_profile.acm_problems_status.get(key, {})
oi_problems_status = user_profile.oi_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 # update submission and accepted number counter
problem.submission_number += 1 problem.submission_number += 1
if self.submission.result == JudgeStatus.ACCEPTED: if self.submission.result == JudgeStatus.ACCEPTED:
problem.accepted_number += 1 problem.accepted_number += 1
# only when submission is not in contest, we update user profile, # submission in a contest will not be counted in user profile
# in other words, users' submission in a contest will not be counted in user profile
if not self.contest_id: if not self.contest_id:
user_profile.submission_number += 1 user_profile.submission_number += 1
if self.submission.result == JudgeStatus.ACCEPTED: if self.submission.result == JudgeStatus.ACCEPTED:
user_profile.accepted_number += 1 user_profile.accepted_number += 1
problem_id = str(self.problem.id)
if self.problem.rule_type == ProblemRuleType.ACM: 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 # update user_profile
if problem_id not in acm_problems_status: if problem_id not in acm_problems_status:
acm_problems_status[problem_id] = {"status": self.submission.result, "_id": self.problem._id} 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 user_profile.acm_problems_status[key] = acm_problems_status
else: 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 # update user_profile
score = self.submission.statistic_info["score"]
if problem_id not in oi_problems_status: if problem_id not in oi_problems_status:
user_profile.add_score(score) user_profile.add_score(score)
oi_problems_status[problem_id] = {"status": self.submission.result, oi_problems_status[problem_id] = {"status": self.submission.result,
@ -218,8 +213,8 @@ class JudgeDispatcher(object):
def update_contest_rank(self): def update_contest_rank(self):
if self.contest_id and self.contest.status != ContestStatus.CONTEST_UNDERWAY: if self.contest_id and self.contest.status != ContestStatus.CONTEST_UNDERWAY:
return return
if self.contest.real_time_rank: if self.contest.rule_type == ContestRuleType.OI or self.contest.real_time_rank:
cache.delete(CacheKey.contest_rank_cache + str(self.contest_id)) cache.delete(f"{CacheKey.contest_rank_cache}:{self.contest.id}")
with transaction.atomic(): with transaction.atomic():
if self.contest.rule_type == ContestRuleType.ACM: if self.contest.rule_type == ContestRuleType.ACM:
acm_rank, _ = ACMContestRank.objects.select_for_update(). \ acm_rank, _ = ACMContestRank.objects.select_for_update(). \

View File

@ -95,6 +95,7 @@ class ProblemAdminSerializer(BaseProblemSerializer):
class ContestProblemAdminSerializer(BaseProblemSerializer): class ContestProblemAdminSerializer(BaseProblemSerializer):
class Meta: class Meta:
model = Problem model = Problem
fields = "__all__"
class ProblemSerializer(BaseProblemSerializer): class ProblemSerializer(BaseProblemSerializer):

View File

@ -21,11 +21,10 @@ class ProblemAPI(APIView):
oi_problems_status = profile.oi_problems_status.get("problems", {}) oi_problems_status = profile.oi_problems_status.get("problems", {})
# paginate data # paginate data
results = queryset_values.get("results") results = queryset_values.get("results")
if results: if results is not None:
problems = results problems = results
else: else:
problems = [queryset_values,] problems = [queryset_values,]
for problem in problems: for problem in problems:
if problem["rule_type"] == ProblemRuleType.ACM: if problem["rule_type"] == ProblemRuleType.ACM:
problem["my_status"] = acm_problems_status.get(str(problem["id"]), {}).get("status") 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") tag_text = request.GET.get("tag")
if tag_text: if tag_text:
try: problems = problems.filter(tags__name=tag_text)
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)
# 搜索的情况 # 搜索的情况
keyword = request.GET.get("keyword", "").strip() keyword = request.GET.get("keyword", "").strip()
@ -76,7 +71,11 @@ class ProblemAPI(APIView):
class ContestProblemAPI(APIView): class ContestProblemAPI(APIView):
def _add_problem_status(self, request, queryset_values): 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 profile = request.user.userprofile
if self.contest.rule_type == ContestRuleType.ACM: if self.contest.rule_type == ContestRuleType.ACM:
problems_status = profile.acm_problems_status.get("contest_problems", {}) problems_status = profile.acm_problems_status.get("contest_problems", {})
@ -96,7 +95,7 @@ class ContestProblemAPI(APIView):
except Problem.DoesNotExist: except Problem.DoesNotExist:
return self.error("Problem does not exist.") return self.error("Problem does not exist.")
problem_data = ContestProblemSerializer(problem).data problem_data = ContestProblemSerializer(problem).data
self._add_problem_status(request, problem_data) self._add_problem_status(request, [problem_data,])
return self.success(problem_data) return self.success(problem_data)
contest_problems = Problem.objects.select_related("created_by").filter(contest=self.contest, visible=True) contest_problems = Problem.objects.select_related("created_by").filter(contest=self.contest, visible=True)

View File

@ -84,14 +84,13 @@ class SubmissionAPI(APIView):
@login_required @login_required
def put(self, request): def put(self, request):
try: try:
submission = Submission.objects.select_related("problem")\ submission = Submission.objects.select_related("problem").get(id=request.data["id"])
.get(id=request.data["id"], contest__isnull=True)
except Submission.DoesNotExist: except Submission.DoesNotExist:
return self.error("Submission doesn't exist") return self.error("Submission doesn't exist")
if not submission.check_user_permission(request.user, check_share=False): if not submission.check_user_permission(request.user, check_share=False):
return self.error("No permission to share the submission") return self.error("No permission to share the submission")
if submission.contest and submission.contest.status == ContestStatus.CONTEST_UNDERWAY: 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.shared = request.data["shared"]
submission.save(update_fields=["shared"]) submission.save(update_fields=["shared"])
return self.success() return self.success()
@ -130,7 +129,7 @@ class ContestSubmissionListAPI(APIView):
return self.error("Limit is needed") return self.error("Limit is needed")
contest = self.contest 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") return self.error("No permission for OI contest submissions")
submissions = Submission.objects.filter(contest_id=contest.id).select_related("problem__created_by") 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) submissions = submissions.filter(create_time__gte=contest.start_time)
# 封榜的时候只能看到自己的提交 # 封榜的时候只能看到自己的提交
if not contest.real_time_rank and not contest.is_contest_admin(request.user): if contest.rule_type == ContestRuleType.ACM:
submissions = submissions.filter(user_id=request.user.id) 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 = self.paginate_data(request, submissions)
data["results"] = SubmissionListSerializer(data["results"], many=True, user=request.user).data data["results"] = SubmissionListSerializer(data["results"], many=True, user=request.user).data
return self.success(data) return self.success(data)

View File

@ -23,6 +23,6 @@ class ContestRuleType(Choices):
class CacheKey: class CacheKey:
waiting_queue = "waiting_queue" waiting_queue = "waiting_queue"
contest_rank_cache = "contest_rank_cache_" contest_rank_cache = "contest_rank_cache"
website_config = "website_config" website_config = "website_config"
option = "option" option = "option"