mirror of
https://github.com/QingdaoU/OnlineJudge.git
synced 2024-09-21 00:13:18 +00:00
ranklist相关的改动
This commit is contained in:
parent
3b1f02c356
commit
07643e2639
25
account/migrations/0003_userprofile_total_score.py
Normal file
25
account/migrations/0003_userprofile_total_score.py
Normal file
@ -0,0 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.6 on 2017-08-20 02:03
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('account', '0002_auto_20170209_1028'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='userprofile',
|
||||
name='total_score',
|
||||
field=models.BigIntegerField(default=0),
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='userprofile',
|
||||
old_name='accepted_problem_number',
|
||||
new_name='accepted_number',
|
||||
),
|
||||
]
|
@ -69,28 +69,38 @@ def _random_avatar():
|
||||
|
||||
class UserProfile(models.Model):
|
||||
user = models.OneToOneField(User)
|
||||
# Store user problem solution status with json string format
|
||||
# {"problems": {1: JudgeStatus.ACCEPTED}, "contest_problems": {20: JudgeStatus.PENDING)}
|
||||
# Store user problem solution status with json string format, Only for problems not contest_problems
|
||||
# ACM: {1: {status: JudgeStatus.ACCEPTED}}
|
||||
# OI: {1: {score: 33}}
|
||||
problems_status = JSONField(default={})
|
||||
avatar = models.CharField(max_length=50, default=_random_avatar)
|
||||
blog = models.URLField(blank=True, null=True)
|
||||
mood = models.CharField(max_length=200, blank=True, null=True)
|
||||
accepted_problem_number = models.IntegerField(default=0)
|
||||
submission_number = models.IntegerField(default=0)
|
||||
phone_number = models.CharField(max_length=15, blank=True, null=True)
|
||||
school = models.CharField(max_length=200, blank=True, null=True)
|
||||
major = models.CharField(max_length=200, blank=True, null=True)
|
||||
student_id = models.CharField(max_length=15, blank=True, null=True)
|
||||
time_zone = models.CharField(max_length=32, blank=True, null=True)
|
||||
language = models.CharField(max_length=32, blank=True, null=True)
|
||||
# for ACM
|
||||
accepted_number = models.IntegerField(default=0)
|
||||
# for OI
|
||||
total_score = models.BigIntegerField(default=0)
|
||||
submission_number = models.IntegerField(default=0)
|
||||
|
||||
def add_accepted_problem_number(self):
|
||||
self.accepted_problem_number = models.F("accepted_problem_number") + 1
|
||||
self.accepted_number = models.F("accepted_number") + 1
|
||||
self.save()
|
||||
|
||||
def add_submission_number(self):
|
||||
self.submission_number = models.F("submission_number") + 1
|
||||
self.save()
|
||||
|
||||
# 计算总分时, 应先减掉上次该题所得分数, 然后再加上本次所得分数
|
||||
def add_score(self, this_time_score, last_time_score=None):
|
||||
last_time_score = last_time_score or 0
|
||||
self.total_score = models.F("total_score") - last_time_score + this_time_score
|
||||
self.save()
|
||||
|
||||
class Meta:
|
||||
db_table = "user_profile"
|
||||
|
@ -1,6 +1,6 @@
|
||||
from django import forms
|
||||
|
||||
from utils.api import DateTimeTZField, serializers
|
||||
from utils.api import DateTimeTZField, serializers, UsernameSerializer
|
||||
|
||||
from .models import AdminType, ProblemPermission, User, UserProfile
|
||||
|
||||
@ -97,3 +97,10 @@ class TwoFactorAuthCodeSerializer(serializers.Serializer):
|
||||
|
||||
class AvatarUploadForm(forms.Form):
|
||||
file = forms.FileField()
|
||||
|
||||
|
||||
class RankInfoSerializer(serializers.ModelSerializer):
|
||||
user = UsernameSerializer()
|
||||
|
||||
class Meta:
|
||||
model = UserProfile
|
||||
|
@ -3,7 +3,8 @@ from django.conf.urls import url
|
||||
from ..views.oj import (ApplyResetPasswordAPI, ResetPasswordAPI,
|
||||
UserChangePasswordAPI, UserRegisterAPI,
|
||||
UserLoginAPI, UserLogoutAPI, UsernameOrEmailCheck,
|
||||
SSOAPI, AvatarUploadAPI, TwoFactorAuthAPI, UserProfileAPI)
|
||||
SSOAPI, AvatarUploadAPI, TwoFactorAuthAPI, UserProfileAPI,
|
||||
UserRankAPI)
|
||||
|
||||
from utils.captcha.views import CaptchaAPIView
|
||||
|
||||
@ -19,5 +20,6 @@ urlpatterns = [
|
||||
url(r"^profile/?$", UserProfileAPI.as_view(), name="user_profile_api"),
|
||||
url(r"^avatar/upload/?$", AvatarUploadAPI.as_view(), name="avatar_upload_api"),
|
||||
url(r"^sso/?$", SSOAPI.as_view(), name="sso_api"),
|
||||
url(r"^two_factor_auth/?$", TwoFactorAuthAPI.as_view(), name="two_factor_auth_api")
|
||||
url(r"^two_factor_auth/?$", TwoFactorAuthAPI.as_view(), name="two_factor_auth_api"),
|
||||
url(r"^user_rank/?$", UserRankAPI.as_view(), name="user_rank_api"),
|
||||
]
|
||||
|
@ -18,10 +18,10 @@ from utils.shortcuts import rand_str
|
||||
|
||||
from ..decorators import login_required
|
||||
from ..models import User, UserProfile
|
||||
from ..serializers import (ApplyResetPasswordSerializer,
|
||||
ResetPasswordSerializer,
|
||||
from ..serializers import (ApplyResetPasswordSerializer, ResetPasswordSerializer,
|
||||
UserChangePasswordSerializer, UserLoginSerializer,
|
||||
UserRegisterSerializer, UsernameOrEmailCheckSerializer)
|
||||
UserRegisterSerializer, UsernameOrEmailCheckSerializer,
|
||||
RankInfoSerializer)
|
||||
from ..serializers import (SSOSerializer, TwoFactorAuthCodeSerializer,
|
||||
UserProfileSerializer,
|
||||
EditUserProfileSerializer, AvatarUploadForm)
|
||||
@ -32,6 +32,7 @@ class UserProfileAPI(APIView):
|
||||
"""
|
||||
判断是否登录, 若登录返回用户信息
|
||||
"""
|
||||
|
||||
@method_decorator(ensure_csrf_cookie)
|
||||
def get(self, request, **kwargs):
|
||||
user = request.user
|
||||
@ -321,3 +322,16 @@ class ResetPasswordAPI(APIView):
|
||||
user.set_password(data["password"])
|
||||
user.save()
|
||||
return self.success("Succeeded")
|
||||
|
||||
|
||||
class UserRankAPI(APIView):
|
||||
def get(self, request):
|
||||
rule_type = request.GET.get("rule")
|
||||
if rule_type not in ["acm", "oi"]:
|
||||
rule_type = "acm"
|
||||
profiles = UserProfile.objects.select_related("user").filter(submission_number__gt=0)
|
||||
if rule_type == "acm":
|
||||
profiles = profiles.order_by("-accepted_number", "submission_number")
|
||||
else:
|
||||
profiles = profiles.order_by("-total_score")
|
||||
return self.success(self.paginate_data(request, profiles, RankInfoSerializer))
|
||||
|
@ -40,7 +40,7 @@ class JudgeDispatcher(object):
|
||||
.get(_id=problem_id, contest_id=self.submission.contest_id)
|
||||
self.contest = self.problem.contest
|
||||
else:
|
||||
self.problem = Problem.objects.get(pk=problem_id)
|
||||
self.problem = Problem.objects.get(_id=problem_id)
|
||||
|
||||
def _request(self, url, data=None):
|
||||
kwargs = {"headers": {"X-Judge-Server-Token": self.token,
|
||||
@ -75,7 +75,7 @@ class JudgeDispatcher(object):
|
||||
def judge(self, output=False):
|
||||
server = self.choose_judge_server()
|
||||
if not server:
|
||||
data = {"submission_id": self.submission.id, "problem_id": self.problem.id}
|
||||
data = {"submission_id": self.submission.id, "problem_id": self.problem._id}
|
||||
self.redis_conn.lpush(CacheKey.waiting_queue, json.dumps(data))
|
||||
return
|
||||
|
||||
@ -111,6 +111,7 @@ class JudgeDispatcher(object):
|
||||
# 用时和内存占用保存为多个测试点中最长的那个
|
||||
self.submission.statistic_info["time_cost"] = max([x["cpu_time"] for x in resp["data"]])
|
||||
self.submission.statistic_info["memory_cost"] = max([x["memory"] for x in resp["data"]])
|
||||
# todo OI statistic_info["score"]
|
||||
|
||||
error_test_case = list(filter(lambda case: case["result"] != 0, resp["data"]))
|
||||
# 多个测试点全部正确则AC,否则 ACM模式下取第一个错误的测试点的状态, OI模式若全部错误则取第一个错误测试点状态,否则为部分正确
|
||||
@ -144,9 +145,9 @@ class JudgeDispatcher(object):
|
||||
self.problem.add_ac_number()
|
||||
with transaction.atomic():
|
||||
if self.submission.contest_id:
|
||||
problem = ContestProblem.objects.select_for_update().get(_id=self.problem.id, contest_id=self.contest.id)
|
||||
problem = ContestProblem.objects.select_for_update().get(_id=self.problem._id, contest_id=self.contest.id)
|
||||
else:
|
||||
problem = Problem.objects.select_related().get(_id=self.problem.id)
|
||||
problem = Problem.objects.select_related().get(_id=self.problem._id)
|
||||
info = problem.statistic_info
|
||||
result = str(self.submission.result)
|
||||
info[result] = info.get(result, 0) + 1
|
||||
@ -155,21 +156,35 @@ class JudgeDispatcher(object):
|
||||
|
||||
def update_user_profile(self):
|
||||
with transaction.atomic():
|
||||
# 更新user profile
|
||||
user = User.objects.select_for_update().get(id=self.submission.user_id)
|
||||
user_profile = user.userprofile
|
||||
user_profile.add_submission_number()
|
||||
problems_status = user_profile.problems_status
|
||||
if "problems" not in problems_status:
|
||||
problems_status["problems"] = {}
|
||||
|
||||
# 之前状态不是ac, 现在是ac了 需要更新用户ac题目数量计数器,这里需要判重
|
||||
if problems_status["problems"].get(str(self.problem.id), JudgeStatus.WRONG_ANSWER) != JudgeStatus.ACCEPTED:
|
||||
if self.submission.result == JudgeStatus.ACCEPTED:
|
||||
user_profile.add_accepted_problem_number()
|
||||
problems_status["problems"][str(self.problem.id)] = JudgeStatus.ACCEPTED
|
||||
problem_id = str(self.problem._id)
|
||||
if self.problem.rule_type == ProblemRuleType.ACM:
|
||||
if problem_id not in problems_status:
|
||||
problems_status[problem_id] = {"status": self.submission.result}
|
||||
if self.submission.result == JudgeStatus.ACCEPTED:
|
||||
user_profile.add_accepted_problem_number()
|
||||
# 以前提交过, ac了直接略过
|
||||
elif problems_status[problem_id]["status"] != JudgeStatus.ACCEPTED:
|
||||
if self.submission.result == JudgeStatus.ACCEPTED:
|
||||
user_profile.add_accepted_problem_number()
|
||||
problems_status[problem_id]["status"] = JudgeStatus.ACCEPTED
|
||||
else:
|
||||
problems_status[problem_id]["status"] = self.submission.result
|
||||
|
||||
else:
|
||||
score = self.submission.statistic_info["score"]
|
||||
if problem_id not in problems_status:
|
||||
user_profile.add_score(score)
|
||||
problems_status[problem_id] = {"score": score}
|
||||
else:
|
||||
problems_status["problems"][str(self.problem.id)] = JudgeStatus.WRONG_ANSWER
|
||||
# 加上本次 减掉上次的score
|
||||
user_profile.add_score(score, problems_status[problem_id]["score"])
|
||||
problems_status[problem_id] = {"score": score}
|
||||
|
||||
user_profile.problems_status = problems_status
|
||||
user_profile.save(update_fields=["problems_status"])
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user