Merge branch 'dev'

* dev:
  修改 admin 界面,ip 太宽了
  jquery选择器参数字符串里多打了一个空格
  修复小组邀请赛的密码验证的问题,感觉之前测试过了呀,结果还是有问题,因为验证密码api里选择比赛时限定比赛类型中只有带密码的公开赛,所以无法验证带密码的小组赛

Conflicts:
	judge_dispatcher/tasks.py
	oj/settings.py
	static/src/js/build.js
	static/src/js/config.js
This commit is contained in:
virusdefender 2015-12-23 00:36:21 +08:00
commit 0483fa2496
18 changed files with 475 additions and 138 deletions

View File

@ -110,7 +110,8 @@ class ContestRank(models.Model):
# 之前已经提交过,但是是错误的,这次提交是正确的。错误的题目不计入罚时 # 之前已经提交过,但是是错误的,这次提交是正确的。错误的题目不计入罚时
self.total_time += (info["ac_time"] + info["error_number"] * 20 * 60) self.total_time += (info["ac_time"] + info["error_number"] * 20 * 60)
problem = ContestProblem.objects.get(id=submission.problem_id) problem = ContestProblem.objects.get(id=submission.problem_id)
if problem.total_accepted_number == 0: # 更新题目计数器在前 所以是1
if problem.total_accepted_number == 1:
info["is_first_ac"] = True info["is_first_ac"] = True
else: else:
@ -128,7 +129,7 @@ class ContestRank(models.Model):
self.total_time += info["ac_time"] self.total_time += info["ac_time"]
problem = ContestProblem.objects.get(id=submission.problem_id) problem = ContestProblem.objects.get(id=submission.problem_id)
if problem.total_accepted_number == 0: if problem.total_accepted_number == 1:
info["is_first_ac"] = True info["is_first_ac"] = True
else: else:

View File

@ -308,7 +308,7 @@ class ContestPasswordVerifyAPIView(APIView):
if serializer.is_valid(): if serializer.is_valid():
data = request.data data = request.data
try: try:
contest = Contest.objects.get(id=data["contest_id"], contest_type=PASSWORD_PROTECTED_CONTEST) contest = Contest.objects.get(id=data["contest_id"], contest_type__in=[PASSWORD_PROTECTED_CONTEST,PASSWORD_PROTECTED_GROUP_CONTEST])
except Contest.DoesNotExist: except Contest.DoesNotExist:
return error_response(u"比赛不存在") return error_response(u"比赛不存在")

View File

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('judge_dispatcher', '0002_auto_20151207_2310'),
]
operations = [
migrations.AddField(
model_name='judgeserver',
name='create_time',
field=models.DateTimeField(auto_now_add=True, null=True),
),
migrations.AddField(
model_name='judgeserver',
name='name',
field=models.CharField(default='judger', max_length=30),
preserve_default=False,
),
]

View File

@ -3,6 +3,7 @@ from django.db import models
class JudgeServer(models.Model): class JudgeServer(models.Model):
name = models.CharField(max_length=30)
ip = models.GenericIPAddressField() ip = models.GenericIPAddressField()
port = models.IntegerField() port = models.IntegerField()
# 这个服务器最大可能运行的判题实例数量 # 这个服务器最大可能运行的判题实例数量
@ -14,6 +15,7 @@ class JudgeServer(models.Model):
lock = models.BooleanField(default=False) lock = models.BooleanField(default=False)
# status 为 false 的时候代表不使用这个服务器 # status 为 false 的时候代表不使用这个服务器
status = models.BooleanField(default=True) status = models.BooleanField(default=True)
create_time = models.DateTimeField(auto_now_add=True, blank=True, null=True)
def use_judge_instance(self): def use_judge_instance(self):
# 因为use 和 release 中间是判题时间,可能这个 model 的数据已经被修改了所以不能直接使用self.xxx否则取到的是旧数据 # 因为use 和 release 中间是判题时间,可能这个 model 的数据已经被修改了所以不能直接使用self.xxx否则取到的是旧数据

View File

@ -0,0 +1,29 @@
# coding=utf-8
import json
from rest_framework import serializers
from .models import JudgeServer
class CreateJudgesSerializer(serializers.Serializer):
name = serializers.CharField(max_length=30)
ip = serializers.IPAddressField()
port = serializers.IntegerField()
# 这个服务器最大可能运行的判题实例数量
max_instance_number = serializers.IntegerField()
token = serializers.CharField(max_length=30)
class EditJudgesSerializer(serializers.Serializer):
id = serializers.IntegerField()
name = serializers.CharField(max_length=30)
ip = serializers.IPAddressField()
port = serializers.IntegerField()
# 这个服务器最大可能运行的判题实例数量
max_instance_number = serializers.IntegerField()
token = serializers.CharField(max_length=30)
status = serializers.BooleanField()
class JudgesSerializer(serializers.ModelSerializer):
class Meta:
model = JudgeServer

View File

@ -90,8 +90,8 @@ class JudgeDispatcher(object):
waiting_submission.delete() waiting_submission.delete()
_judge.delay(submission, time_limit=waiting_submission.time_limit, _judge.delay(submission, time_limit=waiting_submission.time_limit,
memory_limit=waiting_submission.memory_limit, test_case_id=waiting_submission.test_case_id, memory_limit=waiting_submission.memory_limit,
is_waiting_task=True) test_case_id=waiting_submission.test_case_id, is_waiting_task=True)
def update_problem_status(self): def update_problem_status(self):
problem = Problem.objects.get(id=self.submission.problem_id) problem = Problem.objects.get(id=self.submission.problem_id)
@ -119,7 +119,8 @@ class JudgeDispatcher(object):
logger.info("Contest debug mode, id: " + str(contest.id) + ", submission id: " + self.submission.id) logger.info("Contest debug mode, id: " + str(contest.id) + ", submission id: " + self.submission.id)
return return
with transaction.atomic(): with transaction.atomic():
contest_problem = ContestProblem.objects.select_for_update().get(contest=contest, id=self.submission.problem_id) contest_problem = ContestProblem.objects.select_for_update().get(contest=contest,
id=self.submission.problem_id)
contest_problem.add_submission_number() contest_problem.add_submission_number()

71
judge_dispatcher/views.py Normal file
View File

@ -0,0 +1,71 @@
# coding=utf-8
from rest_framework.views import APIView
from account.decorators import super_admin_required
from utils.shortcuts import success_response, serializer_invalid_response, error_response, paginate
from .serializers import CreateJudgesSerializer, JudgesSerializer, EditJudgesSerializer
from .models import JudgeServer
class AdminJudgeServerAPIView(APIView):
@super_admin_required
def post(self, request):
"""
添加判题服务器 json api接口
---
request_serializer: CreateJudgesSerializer
response_serializer: JudgesSerializer
"""
serializer = CreateJudgesSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
judge_server = JudgeServer.objects.create(name=data["name"], ip=data["ip"], port=data["port"],
max_instance_number=data["max_instance_number"],
token=data["token"],
created_by=request.user)
return success_response(JudgesSerializer(judge_server).data)
else:
return serializer_invalid_response(serializer)
@super_admin_required
def put(self, request):
"""
修改判题服务器信息 json api接口
---
request_serializer: EditJudgesSerializer
response_serializer: JudgesSerializer
"""
serializer = EditJudgesSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
try:
judge_server = JudgeServer.objects.get(pk=data["id"])
except JudgeServer.DoesNotExist:
return error_response(u"此判题服务器不存在!")
judge_server.name = data["name"]
judge_server.ip = data["ip"]
judge_server.port = data["port"]
judge_server.max_instance_number = data["max_instance_number"]
judge_server.token = data["token"]
judge_server.status = data["status"]
judge_server.save()
return success_response(JudgesSerializer(judge_server).data)
else:
return serializer_invalid_response(serializer)
@super_admin_required
def get(self, request):
"""
获取全部判题服务器
"""
judge_server_id = request.GET.get("judge_server_id", None)
if judge_server_id:
try:
judge_server = JudgeServer.objects.get(id=judge_server_id)
except JudgeServer.DoesNotExist:
return error_response(u"判题服务器不存在")
return success_response(JudgesSerializer(judge_server).data)
judge_server = JudgeServer.objects.all()
return paginate(request, judge_server, JudgesSerializer)

View File

View File

@ -1,19 +0,0 @@
# coding=utf-8
import redis
import datetime
from rest_framework.views import APIView
from judge.result import result
from django.conf import settings
from utils.shortcuts import success_response
from submission.models import Submission
class QueueLengthMonitorAPIView(APIView):
def get(self, request):
r = redis.Redis(host=settings.redis_config["host"], port=settings.redis_config["port"], db=settings.redis_config["db"])
waiting_number = r.get("judge_queue_length")
if waiting_number is None:
waiting_number = 0
now = datetime.datetime.now()
return success_response({"time": ":".join([str(now.hour), str(now.minute), str(now.second)]),
"count": waiting_number})

View File

@ -23,11 +23,9 @@ from admin.views import AdminTemplateView
from problem.views import TestCaseUploadAPIView, ProblemTagAdminAPIView, ProblemAdminAPIView from problem.views import TestCaseUploadAPIView, ProblemTagAdminAPIView, ProblemAdminAPIView
from submission.views import (SubmissionAPIView, SubmissionAdminAPIView, ContestSubmissionAPIView, from submission.views import (SubmissionAPIView, SubmissionAdminAPIView, ContestSubmissionAPIView,
SubmissionShareAPIView, SubmissionRejudgeAdminAPIView) SubmissionShareAPIView, SubmissionRejudgeAdminAPIView)
from monitor.views import QueueLengthMonitorAPIView from judge_dispatcher.views import AdminJudgeServerAPIView
from utils.views import SimditorImageUploadAPIView from utils.views import SimditorImageUploadAPIView
urlpatterns = [ urlpatterns = [
url("^$", "account.views.index_page", name="index_page"), url("^$", "account.views.index_page", name="index_page"),
@ -57,7 +55,6 @@ urlpatterns = [
url(r'^api/submission/$', SubmissionAPIView.as_view(), name="submission_api"), url(r'^api/submission/$', SubmissionAPIView.as_view(), name="submission_api"),
url(r'^api/group_join/$', JoinGroupAPIView.as_view(), name="group_join_api"), url(r'^api/group_join/$', JoinGroupAPIView.as_view(), name="group_join_api"),
url(r'^api/admin/upload_image/$', SimditorImageUploadAPIView.as_view(), name="simditor_upload_image"), url(r'^api/admin/upload_image/$', SimditorImageUploadAPIView.as_view(), name="simditor_upload_image"),
url(r'^api/admin/announcement/$', AnnouncementAdminAPIView.as_view(), name="announcement_admin_api"), url(r'^api/admin/announcement/$', AnnouncementAdminAPIView.as_view(), name="announcement_admin_api"),
url(r'^api/admin/contest/$', ContestAdminAPIView.as_view(), name="contest_admin_api"), url(r'^api/admin/contest/$', ContestAdminAPIView.as_view(), name="contest_admin_api"),
@ -66,16 +63,17 @@ urlpatterns = [
url(r'^api/admin/group_member/$', GroupMemberAdminAPIView.as_view(), name="group_member_admin_api"), url(r'^api/admin/group_member/$', GroupMemberAdminAPIView.as_view(), name="group_member_admin_api"),
url(r'^api/admin/group/promot_as_admin/$', GroupPrometAdminAPIView.as_view(), name="group_promote_admin_api"), url(r'^api/admin/group/promot_as_admin/$', GroupPrometAdminAPIView.as_view(), name="group_promote_admin_api"),
url(r'^api/admin/problem/$', ProblemAdminAPIView.as_view(), name="problem_admin_api"), url(r'^api/admin/problem/$', ProblemAdminAPIView.as_view(), name="problem_admin_api"),
url(r'^api/admin/contest_problem/$', ContestProblemAdminAPIView.as_view(), name="contest_problem_admin_api"), url(r'^api/admin/contest_problem/$', ContestProblemAdminAPIView.as_view(), name="contest_problem_admin_api"),
url(r'^api/admin/contest_problem/public/', MakeContestProblemPublicAPIView.as_view(), name="make_contest_problem_public"), url(r'^api/admin/contest_problem/public/', MakeContestProblemPublicAPIView.as_view(),
name="make_contest_problem_public"),
url(r'^api/admin/test_case_upload/$', TestCaseUploadAPIView.as_view(), name="test_case_upload_api"), url(r'^api/admin/test_case_upload/$', TestCaseUploadAPIView.as_view(), name="test_case_upload_api"),
url(r'^api/admin/tag/$', ProblemTagAdminAPIView.as_view(), name="problem_tag_admin_api"), url(r'^api/admin/tag/$', ProblemTagAdminAPIView.as_view(), name="problem_tag_admin_api"),
url(r'^api/admin/join_group_request/$', JoinGroupRequestAdminAPIView.as_view(), url(r'^api/admin/join_group_request/$', JoinGroupRequestAdminAPIView.as_view(),
name="join_group_request_admin_api"), name="join_group_request_admin_api"),
url(r'^api/admin/submission/$', SubmissionAdminAPIView.as_view(), name="submission_admin_api_view"), url(r'^api/admin/submission/$', SubmissionAdminAPIView.as_view(), name="submission_admin_api_view"),
url(r'^api/admin/monitor/$', QueueLengthMonitorAPIView.as_view(), name="queue_length_monitor_api"),
url(r'^api/admin/judges/$', AdminJudgeServerAPIView.as_view(), name="judges_admin_api"),
url(r'^contest/(?P<contest_id>\d+)/problem/(?P<contest_problem_id>\d+)/$', "contest.views.contest_problem_page", url(r'^contest/(?P<contest_id>\d+)/problem/(?P<contest_problem_id>\d+)/$', "contest.views.contest_problem_page",
name="contest_problem_page"), name="contest_problem_page"),
@ -94,14 +92,12 @@ urlpatterns = [
url(r'^contests/$', "contest.views.contest_list_page", name="contest_list_page"), url(r'^contests/$', "contest.views.contest_list_page", name="contest_list_page"),
url(r'^contests/(?P<page>\d+)/$', "contest.views.contest_list_page", name="contest_list_page"), url(r'^contests/(?P<page>\d+)/$', "contest.views.contest_list_page", name="contest_list_page"),
url(r'^problem/(?P<problem_id>\d+)/$', "problem.views.problem_page", name="problem_page"), url(r'^problem/(?P<problem_id>\d+)/$', "problem.views.problem_page", name="problem_page"),
url(r'^problems/$', "problem.views.problem_list_page", name="problem_list_page"), url(r'^problems/$', "problem.views.problem_list_page", name="problem_list_page"),
url(r'^problems/(?P<page>\d+)/$', "problem.views.problem_list_page", name="problem_list_page"), url(r'^problems/(?P<page>\d+)/$', "problem.views.problem_list_page", name="problem_list_page"),
url(r'^problem/(?P<problem_id>\d+)/submissions/$', "submission.views.problem_my_submissions_list_page", url(r'^problem/(?P<problem_id>\d+)/submissions/$', "submission.views.problem_my_submissions_list_page",
name="problem_my_submissions_page"), name="problem_my_submissions_page"),
url(r'^submission/(?P<submission_id>\w+)/$', "submission.views.my_submission", name="my_submission_page"), url(r'^submission/(?P<submission_id>\w+)/$', "submission.views.my_submission", name="my_submission_page"),
url(r'^submissions/$', "submission.views.my_submission_list_page", name="my_submission_list_page"), url(r'^submissions/$', "submission.views.my_submission_list_page", name="my_submission_list_page"),
url(r'^submissions/(?P<page>\d+)/$', "submission.views.my_submission_list_page", name="my_submission_list_page"), url(r'^submissions/(?P<page>\d+)/$', "submission.views.my_submission_list_page", name="my_submission_list_page"),
@ -128,8 +124,10 @@ urlpatterns = [
url(r'^api/apply_reset_password/$', ApplyResetPasswordAPIView.as_view(), name="apply_reset_password_api"), url(r'^api/apply_reset_password/$', ApplyResetPasswordAPIView.as_view(), name="apply_reset_password_api"),
url(r'^api/reset_password/$', ResetPasswordAPIView.as_view(), name="apply_reset_password_api"), url(r'^api/reset_password/$', ResetPasswordAPIView.as_view(), name="apply_reset_password_api"),
url(r'^account/settings/$', TemplateView.as_view(template_name="oj/account/settings.html"), name="account_setting_page"), url(r'^account/settings/$', TemplateView.as_view(template_name="oj/account/settings.html"),
url(r'^account/settings/avatar/$', TemplateView.as_view(template_name="oj/account/avatar.html"), name="avatar_settings_page"), name="account_setting_page"),
url(r'^account/settings/avatar/$', TemplateView.as_view(template_name="oj/account/avatar.html"),
name="avatar_settings_page"),
url(r'^account/sso/$', SSOAPIView.as_view(), name="sso_api"), url(r'^account/sso/$', SSOAPIView.as_view(), name="sso_api"),
url(r'^api/account/userprofile/$', UserProfileAPIView.as_view(), name="userprofile_api"), url(r'^api/account/userprofile/$', UserProfileAPIView.as_view(), name="userprofile_api"),
url(r'^reset_password/$', TemplateView.as_view(template_name="oj/account/apply_reset_password.html"), name="apply_reset_password_page"), url(r'^reset_password/$', TemplateView.as_view(template_name="oj/account/apply_reset_password.html"), name="apply_reset_password_page"),

View File

@ -22,46 +22,48 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "bootstrap"], function ($,
} }
var superAdminNav = [ var superAdminNav = [
{ name: "首页", {
children: [{name: "主页", hash: "#index/index"}, name: "首页",
{name: "监控", hash: "#monitor/monitor"}] children: [{name: "主页", hash: "#index/index"},
}, {name: "判题服务器", hash: "#judges/judges"}]
{ },
name: "通用", {
children: [{name: "公告管理", hash: "#announcement/announcement"}, name: "通用",
{name: "用户管理", hash: "#user/user_list"}] children: [{name: "公告管理", hash: "#announcement/announcement"},
}, {name: "用户管理", hash: "#user/user_list"}]
{ },
name: "题目管理", {
children: [{name: "题目列表", hash: "#problem/problem_list"}, name: "题目管理",
{name: "创建题目", hash: "#problem/add_problem"}] children: [{name: "题目列表", hash: "#problem/problem_list"},
}, {name: "创建题目", hash: "#problem/add_problem"}]
{ },
name: "比赛管理", {
children: [{name: "比赛列表", hash: "#contest/contest_list"}, name: "比赛管理",
{name: "创建比赛", hash: "#contest/add_contest"}] children: [{name: "比赛列表", hash: "#contest/contest_list"},
}, {name: "创建比赛", hash: "#contest/add_contest"}]
{ },
name: "小组管理", {
children: [{name: "小组列表", hash: "#group/group"}, name: "小组管理",
{name: "加入小组请求", hash: "#group/join_group_request_list"}] children: [{name: "小组列表", hash: "#group/group"},
} {name: "加入小组请求", hash: "#group/join_group_request_list"}]
}
]; ];
var adminNav = [ var adminNav = [
{ name: "首页", {
children: [{name: "主页", hash: "#index/index"}] name: "首页",
}, children: [{name: "主页", hash: "#index/index"}]
{ },
name: "比赛管理", {
children: [{name: "比赛列表", hash: "#contest/contest_list"}, name: "比赛管理",
{name: "创建比赛", hash: "#contest/add_contest"}] children: [{name: "比赛列表", hash: "#contest/contest_list"},
}, {name: "创建比赛", hash: "#contest/add_contest"}]
{ },
name: "小组管理", {
children: [{name: "小组列表", hash: "#group/group"}, name: "小组管理",
{name: "加入小组请求", hash: "#group/join_group_request_list"}] children: [{name: "小组列表", hash: "#group/group"},
} {name: "加入小组请求", hash: "#group/join_group_request_list"}]
}
]; ];
var vm = avalon.define({ var vm = avalon.define({
@ -79,7 +81,7 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "bootstrap"], function ($,
hide_loading: function () { hide_loading: function () {
$("#loading-gif").hide(); $("#loading-gif").hide();
}, },
getLiId: function(hash){ getLiId: function (hash) {
return hash.replace("#", "li-").replace("/", "-"); return hash.replace("#", "li-").replace("/", "-");
} }
}); });
@ -89,14 +91,14 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "bootstrap"], function ($,
url: "/api/user/", url: "/api/user/",
method: "get", method: "get",
dataType: "json", dataType: "json",
success: function(data){ success: function (data) {
if(!data.code){ if (!data.code) {
vm.username = data.data.username; vm.username = data.data.username;
vm.adminType = data.data.admin_type; vm.adminType = data.data.admin_type;
if (data.data.admin_type == 2){ if (data.data.admin_type == 2) {
vm.adminNavList = superAdminNav; vm.adminNavList = superAdminNav;
} }
else{ else {
vm.adminNavList = adminNav; vm.adminNavList = adminNav;
} }
} }
@ -104,7 +106,6 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "bootstrap"], function ($,
}); });
avalon.scan(); avalon.scan();
window.onhashchange = function () { window.onhashchange = function () {
@ -115,12 +116,14 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "bootstrap"], function ($,
show_template("template/" + hash + ".html"); show_template("template/" + hash + ".html");
} }
}; };
setTimeout(function(){li_active("#li-" + hash.replace("/", "-"));}, 500); setTimeout(function () {
li_active("#li-" + hash.replace("/", "-"));
}, 500);
$.ajaxSetup({ $.ajaxSetup({
beforeSend: csrfTokenHeader, beforeSend: csrfTokenHeader,
dataType: "json", dataType: "json",
error: function(){ error: function () {
bsAlert("请求失败"); bsAlert("请求失败");
} }
}); });

View File

@ -0,0 +1,143 @@
require(["jquery", "avalon", "csrfToken", "bsAlert", "validator", "pager"],
function ($, avalon, csrfTokenHeader, bsAlert, editor) {
avalon.ready(function () {
if (avalon.vmodels.judges) {
var vm = avalon.vmodels.judges;
}
else {
var vm = avalon.define({
$id: "judges",
judgesList: [],
isEditing: false,
showEnableOnly: false,
//编辑器同步变量
max_instance_number: 0,
ipAddress: "",
port: 0,
status: true,
judgesId: -1,
name: "",
token: "",
id: 0,
pager: {
getPage: function (page) {
getPage(page);
}
},
editJudges: function (judges) {
vm.id = judges.id;
vm.name = judges.name;
vm.judgesId = judges.id;
vm.status = judges.status;
vm.port = judges.port;
vm.ipAddress = judges.ip;
vm.max_instance_number = judges.max_instance_number;
vm.token = judges.token;
vm.isEditing = true;
},
cancelEdit: function () {
vm.isEditing = false;
}
});
vm.$watch("showEnableOnly", function () {
getPage(1);
avalon.vmodels.judgesPager.currentPage = 1;
});
}
function getPage(page) {
var url = "/api/admin/judges/?paging=true&page=" + page + "&page_size=20";
if (vm.showEnableNnly)
url += "&status=true";
$.ajax({
url: url,
method: "get",
success: function (data) {
if (!data.code) {
vm.judgesList = data.data.results;
avalon.vmodels.judgesPager.totalPage = data.data.total_page;
}
else {
bsAlert(data.data);
}
}
});
}
$("#judges-form").validator().on('submit', function (e) {
if (!e.isDefaultPrevented()) {
var name = $("#name").val();
var max_instance_number = $("#max_instance_number").val();
var ip = $("#ipAddress").val();
var port = $("#port").val();
var token = $("#token").val();
$.ajax({
url: "/api/admin/judges/",
contentType: "application/json",
data: JSON.stringify({
name: name,
ip: ip,
port: port,
token: token,
max_instance_number: max_instance_number
}),
dataType: "json",
method: "post",
success: function (data) {
if (!data.code) {
bsAlert("提交成功!");
$("#name").val("");
$("#max_instance_number").val("");
$("#ipAddress").val("");
$("#port").val("");
$("#token").val("");
getPage(1);
} else {
bsAlert(data.data);
}
}
});
return false;
}
});
$("#edit-judges-form").validator().on('submit', function (e) {
if (!e.isDefaultPrevented()) {
var name = vm.name;
var max_instance_number = vm.max_instance_number;
var ip = vm.ipAddress;
var port = vm.port;
var token = vm.token;
var status = vm.status;
var id = vm.id;
$.ajax({
url: "/api/admin/judges/",
contentType: "application/json",
data: JSON.stringify({
id: id,
name: name,
ip: ip,
port: port,
token: token,
max_instance_number: max_instance_number,
status: status
}),
dataType: "json",
method: "put",
success: function (data) {
if (!data.code) {
bsAlert("提交成功!");
getPage(1);
} else {
bsAlert(data.data);
}
}
});
return false;
}
});
});
avalon.scan();
});

View File

@ -1,48 +0,0 @@
require(["jquery", "chart"], function ($, Chart) {
var data = {
labels: ["初始化"],
datasets: [
{
label: "队列长度",
fillColor: "rgba(255,255,255,0.2)",
strokeColor: "rgba(151,187,205,1)",
pointColor: "rgba(151,187,205,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(151,187,205,1)",
data: [0]
}
]
};
var chart = new Chart($("#waiting-queue-chart").get(0).getContext("2d")).Line(data);
var dataCounter = 0;
function getMonitorData(){
var hash = location.hash;
if (hash != "#monitor/monitor"){
clearInterval(intervalId);
}
$.ajax({
url: "/api/admin/monitor/",
method: "get",
dataType: "json",
success: function(data){
if(!data.code){
chart.addData([data.data["count"]], data.data["time"])
dataCounter ++;
}
}
})
}
$("#clear-chart-data").click(function(){
for(var i = 0;i < dataCounter;i++) {
chart.removeData();
}
dataCounter = 0;
});
var intervalId = setInterval(getMonitorData, 3000);
});

View File

@ -10,7 +10,7 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c
$('form').validator().on('submit', function (e) { $('form').validator().on('submit', function (e) {
e.preventDefault(); e.preventDefault();
var newPassword = $("#new_password ").val(); var newPassword = $("#new_password").val();
var password = $("#password").val(); var password = $("#password").val();
var captcha = $("#captcha").val(); var captcha = $("#captcha").val();
$.ajax({ $.ajax({

View File

@ -68,7 +68,6 @@
addContest_13_pack: "app/admin/contest/addContest", addContest_13_pack: "app/admin/contest/addContest",
contestPassword_14_pack: "app/oj/contest/contestPassword", contestPassword_14_pack: "app/oj/contest/contestPassword",
changePassword_15_pack: "app/oj/account/changePassword", changePassword_15_pack: "app/oj/account/changePassword",
monitor_16_pack: "app/admin/monitor/monitor",
editProblem_17_pack: "app/admin/contest/editProblem", editProblem_17_pack: "app/admin/contest/editProblem",
joinGroupRequestList_18_pack: "app/admin/group/joinGroupRequestList", joinGroupRequestList_18_pack: "app/admin/group/joinGroupRequestList",
group_19_pack: "app/oj/group/group", group_19_pack: "app/oj/group/group",
@ -138,9 +137,6 @@
{ {
name: "changePassword_15_pack" name: "changePassword_15_pack"
}, },
{
name: "monitor_16_pack"
},
{ {
name: "editProblem_17_pack" name: "editProblem_17_pack"
}, },

View File

@ -70,7 +70,6 @@ var require = {
addContest_13_pack: "app/admin/contest/addContest", addContest_13_pack: "app/admin/contest/addContest",
contestPassword_14_pack: "app/oj/contest/contestPassword", contestPassword_14_pack: "app/oj/contest/contestPassword",
changePassword_15_pack: "app/oj/account/changePassword", changePassword_15_pack: "app/oj/account/changePassword",
monitor_16_pack: "app/admin/monitor/monitor",
editProblem_17_pack: "app/admin/contest/editProblem", editProblem_17_pack: "app/admin/contest/editProblem",
joinGroupRequestList_18_pack: "app/admin/group/joinGroupRequestList", joinGroupRequestList_18_pack: "app/admin/group/joinGroupRequestList",
group_19_pack: "app/oj/group/group", group_19_pack: "app/oj/group/group",

View File

@ -0,0 +1,131 @@
<div ms-controller="judges" class="col-md-9">
<h1>判题服务器管理</h1>
<table class="table table-striped">
<tr>
<th>编号</th>
<th>名字</th>
<th>最大实例数量</th>
<th>负载</th>
<th>创建时间</th>
<th>状态</th>
<th></th>
</tr>
<tr ms-repeat="judgesList">
<td>{{ el.id }}</td>
<td>{{ el.name }}</td>
<td>{{ el.max_instance_number }}</td>
<td>{{ el.workload }}</td>
<td>{{ el.create_time|date("yyyy-MM-dd HH:mm:ss")}}</td>
<td ms-text="el.status?'启用':'停用'"></td>
<td>
<button class="btn-sm btn-info" ms-click="editJudges(el)">编辑</button>
</td>
</tr>
</table>
<div class="form-group">
<label>仅显示启用 <input ms-duplex-checked="showEnableOnly" type="checkbox"/></label>
</div>
<div class="right">
<ms:pager $id="judgesPager" config="pager"></ms:pager>
</div>
<div ms-visible="isEditing">
<h3>编辑判题服务器</h3>
<form id="edit-judges-form">
<div class="col-md-12">
<div class="col-md-6">
<div class="form-group">
<label>名字</label>
<input name="title" type="text" class="form-control" placeholder="名字" maxlength="30" ms-duplex="name" required data-error="请填写合法的服务器名称">
<div class="help-block with-errors"></div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label>口令</label>
<input name="title" type="text" class="form-control" ms-duplex="token" placeholder="口令" maxlength="30" required data-error="请填写合法的口令">
<div class="help-block with-errors"></div>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label>IP</label>
<input name="ip" type="text" class="form-control" ms-duplex="ipAddress" placeholder="IP" required data-error="请填写合法的IP地址">
<div class="help-block with-errors"></div>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label>端口</label>
<input name="port" type="number" class="form-control" ms-duplex="port" placeholder="端口" required data-error="请填写合法的端口号">
<div class="help-block with-errors"></div>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label>最大实例数量</label>
<input type="number" class="form-control" placeholder="最大实例数量" ms-duplex="max_instance_number" required data-error="请填写合法的最大实例数量">
<div class="help-block with-errors"></div>
</div>
</div>
<div class="form-group">
<label>启用 <input ms-duplex-checked="status" type="checkbox"/></label>
</div>
<div class="form-group">
<button class="btn btn-success">保存修改</button>
&nbsp;&nbsp;
<a ms-click="cancelEdit()" class="btn btn-danger">取消</a>
</div>
</div>
</form>
</div>
<h3>添加判题服务器</h3>
<form id="judges-form">
<div class="form-group">
<div class="col-md-12">
<div class="col-md-6">
<div class="form-group">
<label>名字</label>
<input name="title" type="text" class="form-control" id="name" placeholder="名字" maxlength="30" required data-error="请填写合法的服务器名称">
<div class="help-block with-errors"></div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label>口令</label>
<input name="title" type="text" class="form-control" id="token" placeholder="口令" maxlength="30" required data-error="请填写合法的口令">
<div class="help-block with-errors"></div>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label>IP</label>
<input name="ip" type="text" class="form-control" id="ipAddress" placeholder="IP" required data-error="请填写合法的IP地址">
<div class="help-block with-errors"></div>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label>端口</label>
<input name="port" type="number" class="form-control" id="port" placeholder="端口" required data-error="请填写合法的端口号">
<div class="help-block with-errors"></div>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label>最大实例数量</label>
<input type="number" class="form-control" placeholder="最大实例数量" id="max_instance_number" required data-error="请填写合法的最大实例数量">
<div class="help-block with-errors"></div>
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-success">添加</button>
</div>
</div>
</form>
</div>
<script src="/static/js/app/admin/judges/judges.js"></script>

View File

@ -2,6 +2,7 @@
import hashlib import hashlib
import time import time
import random import random
import logging
from django.shortcuts import render from django.shortcuts import render
from django.core.paginator import Paginator from django.core.paginator import Paginator
@ -9,6 +10,9 @@ from django.core.paginator import Paginator
from rest_framework.response import Response from rest_framework.response import Response
logger = logging.getLogger("app_info")
def error_page(request, error_reason): def error_page(request, error_reason):
return render(request, "utils/error.html", {"error": error_reason}) return render(request, "utils/error.html", {"error": error_reason})
@ -96,7 +100,8 @@ def paginate_data(request, query_set, object_serializer):
def paginate(request, query_set, object_serializer=None): def paginate(request, query_set, object_serializer=None):
try: try:
data= paginate_data(request, query_set, object_serializer) data= paginate_data(request, query_set, object_serializer)
except Exception: except Exception as e:
logger.error(str(e))
return error_response(u"参数错误") return error_response(u"参数错误")
return success_response(data) return success_response(data)