mirror of
https://github.com/QingdaoU/OnlineJudge.git
synced 2024-09-21 08:23:20 +00:00
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:
commit
0483fa2496
@ -110,7 +110,8 @@ class ContestRank(models.Model):
|
||||
# 之前已经提交过,但是是错误的,这次提交是正确的。错误的题目不计入罚时
|
||||
self.total_time += (info["ac_time"] + info["error_number"] * 20 * 60)
|
||||
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
|
||||
|
||||
else:
|
||||
@ -128,7 +129,7 @@ class ContestRank(models.Model):
|
||||
self.total_time += info["ac_time"]
|
||||
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
|
||||
|
||||
else:
|
||||
|
@ -308,7 +308,7 @@ class ContestPasswordVerifyAPIView(APIView):
|
||||
if serializer.is_valid():
|
||||
data = request.data
|
||||
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:
|
||||
return error_response(u"比赛不存在")
|
||||
|
||||
|
25
judge_dispatcher/migrations/0003_auto_20151223_0029.py
Normal file
25
judge_dispatcher/migrations/0003_auto_20151223_0029.py
Normal 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,
|
||||
),
|
||||
]
|
@ -3,6 +3,7 @@ from django.db import models
|
||||
|
||||
|
||||
class JudgeServer(models.Model):
|
||||
name = models.CharField(max_length=30)
|
||||
ip = models.GenericIPAddressField()
|
||||
port = models.IntegerField()
|
||||
# 这个服务器最大可能运行的判题实例数量
|
||||
@ -14,6 +15,7 @@ class JudgeServer(models.Model):
|
||||
lock = models.BooleanField(default=False)
|
||||
# status 为 false 的时候代表不使用这个服务器
|
||||
status = models.BooleanField(default=True)
|
||||
create_time = models.DateTimeField(auto_now_add=True, blank=True, null=True)
|
||||
|
||||
def use_judge_instance(self):
|
||||
# 因为use 和 release 中间是判题时间,可能这个 model 的数据已经被修改了,所以不能直接使用self.xxx,否则取到的是旧数据
|
||||
|
29
judge_dispatcher/serializers.py
Normal file
29
judge_dispatcher/serializers.py
Normal 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
|
@ -90,8 +90,8 @@ class JudgeDispatcher(object):
|
||||
waiting_submission.delete()
|
||||
|
||||
_judge.delay(submission, time_limit=waiting_submission.time_limit,
|
||||
memory_limit=waiting_submission.memory_limit, test_case_id=waiting_submission.test_case_id,
|
||||
is_waiting_task=True)
|
||||
memory_limit=waiting_submission.memory_limit,
|
||||
test_case_id=waiting_submission.test_case_id, is_waiting_task=True)
|
||||
|
||||
def update_problem_status(self):
|
||||
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)
|
||||
return
|
||||
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()
|
||||
|
||||
|
71
judge_dispatcher/views.py
Normal file
71
judge_dispatcher/views.py
Normal 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)
|
@ -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})
|
20
oj/urls.py
20
oj/urls.py
@ -23,11 +23,9 @@ from admin.views import AdminTemplateView
|
||||
from problem.views import TestCaseUploadAPIView, ProblemTagAdminAPIView, ProblemAdminAPIView
|
||||
from submission.views import (SubmissionAPIView, SubmissionAdminAPIView, ContestSubmissionAPIView,
|
||||
SubmissionShareAPIView, SubmissionRejudgeAdminAPIView)
|
||||
from monitor.views import QueueLengthMonitorAPIView
|
||||
from judge_dispatcher.views import AdminJudgeServerAPIView
|
||||
from utils.views import SimditorImageUploadAPIView
|
||||
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
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/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/announcement/$', AnnouncementAdminAPIView.as_view(), name="announcement_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/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/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/tag/$', ProblemTagAdminAPIView.as_view(), name="problem_tag_admin_api"),
|
||||
url(r'^api/admin/join_group_request/$', JoinGroupRequestAdminAPIView.as_view(),
|
||||
name="join_group_request_admin_api"),
|
||||
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",
|
||||
name="contest_problem_page"),
|
||||
@ -94,14 +92,12 @@ urlpatterns = [
|
||||
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'^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/(?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",
|
||||
name="problem_my_submissions_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/(?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/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/avatar/$', TemplateView.as_view(template_name="oj/account/avatar.html"), name="avatar_settings_page"),
|
||||
url(r'^account/settings/$', TemplateView.as_view(template_name="oj/account/settings.html"),
|
||||
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'^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"),
|
||||
|
@ -22,9 +22,10 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "bootstrap"], function ($,
|
||||
}
|
||||
|
||||
var superAdminNav = [
|
||||
{ name: "首页",
|
||||
{
|
||||
name: "首页",
|
||||
children: [{name: "主页", hash: "#index/index"},
|
||||
{name: "监控", hash: "#monitor/monitor"}]
|
||||
{name: "判题服务器", hash: "#judges/judges"}]
|
||||
},
|
||||
{
|
||||
name: "通用",
|
||||
@ -49,7 +50,8 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "bootstrap"], function ($,
|
||||
];
|
||||
|
||||
var adminNav = [
|
||||
{ name: "首页",
|
||||
{
|
||||
name: "首页",
|
||||
children: [{name: "主页", hash: "#index/index"}]
|
||||
},
|
||||
{
|
||||
@ -104,7 +106,6 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "bootstrap"], function ($,
|
||||
});
|
||||
|
||||
|
||||
|
||||
avalon.scan();
|
||||
|
||||
window.onhashchange = function () {
|
||||
@ -115,7 +116,9 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "bootstrap"], function ($,
|
||||
show_template("template/" + hash + ".html");
|
||||
}
|
||||
};
|
||||
setTimeout(function(){li_active("#li-" + hash.replace("/", "-"));}, 500);
|
||||
setTimeout(function () {
|
||||
li_active("#li-" + hash.replace("/", "-"));
|
||||
}, 500);
|
||||
|
||||
$.ajaxSetup({
|
||||
beforeSend: csrfTokenHeader,
|
||||
|
143
static/src/js/app/admin/judges/judges.js
Normal file
143
static/src/js/app/admin/judges/judges.js
Normal 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();
|
||||
});
|
@ -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);
|
||||
|
||||
});
|
@ -68,7 +68,6 @@
|
||||
addContest_13_pack: "app/admin/contest/addContest",
|
||||
contestPassword_14_pack: "app/oj/contest/contestPassword",
|
||||
changePassword_15_pack: "app/oj/account/changePassword",
|
||||
monitor_16_pack: "app/admin/monitor/monitor",
|
||||
editProblem_17_pack: "app/admin/contest/editProblem",
|
||||
joinGroupRequestList_18_pack: "app/admin/group/joinGroupRequestList",
|
||||
group_19_pack: "app/oj/group/group",
|
||||
@ -138,9 +137,6 @@
|
||||
{
|
||||
name: "changePassword_15_pack"
|
||||
},
|
||||
{
|
||||
name: "monitor_16_pack"
|
||||
},
|
||||
{
|
||||
name: "editProblem_17_pack"
|
||||
},
|
||||
|
@ -70,7 +70,6 @@ var require = {
|
||||
addContest_13_pack: "app/admin/contest/addContest",
|
||||
contestPassword_14_pack: "app/oj/contest/contestPassword",
|
||||
changePassword_15_pack: "app/oj/account/changePassword",
|
||||
monitor_16_pack: "app/admin/monitor/monitor",
|
||||
editProblem_17_pack: "app/admin/contest/editProblem",
|
||||
joinGroupRequestList_18_pack: "app/admin/group/joinGroupRequestList",
|
||||
group_19_pack: "app/oj/group/group",
|
||||
|
131
template/src/admin/judges/judges.html
Normal file
131
template/src/admin/judges/judges.html
Normal 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>
|
||||
|
||||
<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>
|
@ -2,6 +2,7 @@
|
||||
import hashlib
|
||||
import time
|
||||
import random
|
||||
import logging
|
||||
|
||||
from django.shortcuts import render
|
||||
from django.core.paginator import Paginator
|
||||
@ -9,6 +10,9 @@ from django.core.paginator import Paginator
|
||||
from rest_framework.response import Response
|
||||
|
||||
|
||||
logger = logging.getLogger("app_info")
|
||||
|
||||
|
||||
def error_page(request, 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):
|
||||
try:
|
||||
data= paginate_data(request, query_set, object_serializer)
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
logger.error(str(e))
|
||||
return error_response(u"参数错误")
|
||||
return success_response(data)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user