Accept Merge Request #257 增加比赛倒计时 api;修复小 bug : (virusdefender-dev -> dev)

Merge Request: 增加比赛倒计时 api;修复小 bug
Created By: @virusdefender
Accepted By: @virusdefender
URL: https://coding.net/u/virusdefender/p/qduoj/git/merge/257
This commit is contained in:
virusdefender
2015-09-20 23:34:22 +08:00
7 changed files with 89 additions and 33 deletions

View File

@@ -7,7 +7,7 @@ from .models import User
class UserLoginSerializer(serializers.Serializer): class UserLoginSerializer(serializers.Serializer):
username = serializers.CharField(max_length=30) username = serializers.CharField(max_length=30)
password = serializers.CharField(max_length=30) password = serializers.CharField(max_length=30)
captcha = serializers.CharField(required=False,min_length=4,max_length=4) captcha = serializers.CharField(required=False, min_length=4, max_length=4)
class UsernameCheckSerializer(serializers.Serializer): class UsernameCheckSerializer(serializers.Serializer):

View File

@@ -26,17 +26,15 @@ class UserLoginAPIView(APIView):
serializer = UserLoginSerializer(data=request.data) serializer = UserLoginSerializer(data=request.data)
if serializer.is_valid(): if serializer.is_valid():
data = serializer.data data = serializer.data
user = User.objects.get(username=data["username"]) user = auth.authenticate(username=data["username"], password=data["password"])
# 只有管理员才适用验证码登录 # 用户名或密码错误的话 返回None
if user:
if user.admin_type > 0: if user.admin_type > 0:
if not "captcha" in data: if "captcha" not in data:
return error_response(u"请填写验证码!") return error_response(u"请填写验证码!")
captcha = Captcha(request) captcha = Captcha(request)
if not captcha.check(data["captcha"]): if not captcha.check(data["captcha"]):
return error_response(u"验证码错误") return error_response(u"验证码错误")
user = auth.authenticate(username=data["username"], password=data["password"])
# 用户名或密码错误的话 返回None
if user:
auth.login(request, user) auth.login(request, user)
return success_response(u"登录成功") return success_response(u"登录成功")
else: else:

View File

@@ -7,6 +7,8 @@ from django.db import IntegrityError
from django.utils import dateparse from django.utils import dateparse
from django.db.models import Q, Sum from django.db.models import Q, Sum
from django.core.paginator import Paginator from django.core.paginator import Paginator
from django.utils.timezone import now
from rest_framework.views import APIView from rest_framework.views import APIView
from utils.shortcuts import (serializer_invalid_response, error_response, from utils.shortcuts import (serializer_invalid_response, error_response,
@@ -454,3 +456,22 @@ def contest_rank_page(request, contest_id):
"auto_refresh": request.GET.get("auto_refresh", None) == "true", "auto_refresh": request.GET.get("auto_refresh", None) == "true",
"show_real_name": request.GET.get("show_real_name", None) == "true", "show_real_name": request.GET.get("show_real_name", None) == "true",
"real_time_rank": contest.real_time_rank}) "real_time_rank": contest.real_time_rank})
class ContestTimeAPIView(APIView):
"""
获取比赛开始或者结束的倒计时,返回毫秒数字
"""
def get(self, request):
t = request.GET.get("type", "start")
contest_id = request.GET.get("contest_id", -1)
try:
contest = Contest.objects.get(id=contest_id)
except Contest.DoesNotExist:
return error_response(u"比赛不存在")
if t == "start":
# 距离开始还有多长时间
return success_response(int((contest.start_time - now()).total_seconds() * 1000))
else:
# 距离结束还有多长时间
return success_response(int((contest.end_time - now()).total_seconds() * 1000))

View File

@@ -98,16 +98,17 @@ class JudgeClient(object):
def _compare_output(self, test_case_id): def _compare_output(self, test_case_id):
test_case_config = self._test_case_info["test_cases"][str(test_case_id)] test_case_config = self._test_case_info["test_cases"][str(test_case_id)]
test_case_md5 = test_case_config["output_md5"]
output_path = judger_workspace + str(test_case_id) + ".out" output_path = judger_workspace + str(test_case_id) + ".out"
try: try:
f = open(output_path, "rb") f = open(output_path, "rb")
except IOError: except IOError:
# 文件不存在等引发的异常 返回结果错误 # 文件不存在等引发的异常 返回结果错误
return False return "", False
if "striped_output_md5" not in test_case_config:
# 计算输出文件的md5 和之前测试用例文件的md5进行比较 # 计算输出文件的md5 和之前测试用例文件的md5进行比较
# 兼容之前没有striped_output_md5的测试用例
# 现在比较的是完整的文件 # 现在比较的是完整的文件
md5 = hashlib.md5() md5 = hashlib.md5()
while True: while True:
@@ -115,19 +116,16 @@ class JudgeClient(object):
if not data: if not data:
break break
md5.update(data) md5.update(data)
output_md5 = md5.hexdigest()
if md5.hexdigest() == test_case_md5: return output_md5, output_md5 == test_case_config["output_md5"]
return True
else: else:
# 这时候需要去除用户输出最后的空格和换行 再去比较md5 # 这时候需要去除用户输出最后的空格和换行 再去比较md5
# 兼容之前没有striped_output_md5的测试用例 md5 = hashlib.md5()
if "striped_output_md5" not in test_case_config:
return False
f.seek(0)
striped_md5 = hashlib.md5()
# 比较和返回去除空格后的md5比较结果 # 比较和返回去除空格后的md5比较结果
striped_md5.update(f.read().rstrip()) md5.update(f.read().rstrip())
return striped_md5.hexdigest() == test_case_config["striped_output_md5"] output_md5 = md5.hexdigest()
return output_md5, output_md5 == test_case_config["striped_output_md5"]
def _judge_one(self, test_case_id): def _judge_one(self, test_case_id):
# 运行lrun程序 接收返回值 # 运行lrun程序 接收返回值
@@ -157,10 +155,12 @@ class JudgeClient(object):
return run_result return run_result
# 下面就是代码正常运行了 需要判断代码的输出是否正确 # 下面就是代码正常运行了 需要判断代码的输出是否正确
if self._compare_output(test_case_id): output_md5, r = self._compare_output(test_case_id)
if r:
run_result["result"] = result["accepted"] run_result["result"] = result["accepted"]
else: else:
run_result["result"] = result["wrong_answer"] run_result["result"] = result["wrong_answer"]
run_result["output_md5"] = output_md5
return run_result return run_result

View File

@@ -8,7 +8,8 @@ from account.views import (UserLoginAPIView, UsernameCheckAPIView, UserRegisterA
from announcement.views import AnnouncementAdminAPIView from announcement.views import AnnouncementAdminAPIView
from contest.views import ContestAdminAPIView, ContestProblemAdminAPIView, ContestPasswordVerifyAPIView from contest.views import (ContestAdminAPIView, ContestProblemAdminAPIView,
ContestPasswordVerifyAPIView, ContestTimeAPIView)
from group.views import (GroupAdminAPIView, GroupMemberAdminAPIView, from group.views import (GroupAdminAPIView, GroupMemberAdminAPIView,
JoinGroupAPIView, JoinGroupRequestAdminAPIView) JoinGroupAPIView, JoinGroupRequestAdminAPIView)
@@ -25,7 +26,6 @@ from contest_submission.views import contest_problem_my_submissions_list_page
urlpatterns = [ urlpatterns = [
url(r'^install/$', "install.views.install"),
url("^$", "account.views.index_page", name="index_page"), url("^$", "account.views.index_page", name="index_page"),
url(r'^docs/', include('rest_framework_swagger.urls')), url(r'^docs/', include('rest_framework_swagger.urls')),
url(r'^admin/$', TemplateView.as_view(template_name="admin/admin.html"), name="admin_spa_page"), url(r'^admin/$', TemplateView.as_view(template_name="admin/admin.html"), name="admin_spa_page"),
@@ -117,4 +117,6 @@ urlpatterns = [
url(r'^captcha/$', "utils.captcha.views.show_captcha", name="show_captcha"), url(r'^captcha/$', "utils.captcha.views.show_captcha", name="show_captcha"),
url(r'^api/account_security_check/$', AccountSecurityAPIView.as_view(), name="account_security_check"), url(r'^api/account_security_check/$', AccountSecurityAPIView.as_view(), name="account_security_check"),
url(r'^api/contest/time/$', ContestTimeAPIView.as_view(), name="contest_time_api_view"),
] ]

View File

@@ -86,7 +86,7 @@ require(["jquery", "codeMirror", "csrfToken", "bsAlert", "ZeroClipboard"],
function getResult() { function getResult() {
if (counter++ > 10) { if (counter++ > 10) {
hideLoading(); hideLoading();
bsAlert("抱歉,服务器可能出现了故障,请稍后到我的提交列表中查看"); bsAlert("抱歉,服务器正在紧张判题中,请稍后到我的提交列表中查看");
counter = 0; counter = 0;
return; return;
} }
@@ -130,6 +130,39 @@ require(["jquery", "codeMirror", "csrfToken", "bsAlert", "ZeroClipboard"],
} }
} }
function getServerTime(){
var contestId = location.pathname.split("/")[2];
var time = 0;
$.ajax({
url: "/api/contest/time/?contest_id=" + contestId + "&type=end",
dataType: "json",
method: "get",
async: false,
success: function(data){
if(!data.code){
time = data.data;
}
},
error: function(){
time = new Date().getTime();
}
});
return time;
}
if(location.href.indexOf("contest") > -1) {
setInterval(function () {
var time = getServerTime();
var minutes = parseInt(time / (1000 * 60));
if(minutes == 0){
bsAlert("比赛即将结束");
}
else if(minutes > 0 && minutes <= 5){
bsAlert("比赛还剩" + minutes.toString() + "分钟");
}
}, 1000 * 60);
}
$("#submit-code-button").click(function () { $("#submit-code-button").click(function () {
var code = codeEditor.getValue(); var code = codeEditor.getValue();

View File

@@ -45,7 +45,9 @@ java -cp {exe_path} Main</pre>
<li>C/C++ 的64位整数类型请使用 <code>long long</code> 声明,使用 <code>cin/cout</code><code>%lld</code> 输入输出。 <li>C/C++ 的64位整数类型请使用 <code>long long</code> 声明,使用 <code>cin/cout</code><code>%lld</code> 输入输出。
使用<code>__int64</code>会导致编译错误。</li> 使用<code>__int64</code>会导致编译错误。</li>
<li>程序执行时间指CPU时间占用内存按执行过程中内存消耗的峰值计有多组测试数据时以最大的时间和内存消耗为准</li> <li>程序执行时间指CPU时间占用内存按执行过程中内存消耗的峰值计有多组测试数据时以最大的时间和内存消耗为准</li>
<li>判题的时候会去除你的输出的最后的换行和空格,然后与去除最后的换行和空格的答案做比较,如果不一致就是 Wrong Answer。
其余的行末空格和空行不去除,看清楚题目的要求。没有格式错误。
</li>
</ul> </ul>
</div> </div>
</div> </div>