mirror of
https://github.com/QingdaoU/OnlineJudge.git
synced 2024-09-21 16:33:22 +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)
|
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:
|
||||||
|
@ -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"比赛不存在")
|
||||||
|
|
||||||
|
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):
|
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,否则取到的是旧数据
|
||||||
|
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()
|
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
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 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"),
|
||||||
|
@ -22,9 +22,10 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "bootstrap"], function ($,
|
|||||||
}
|
}
|
||||||
|
|
||||||
var superAdminNav = [
|
var superAdminNav = [
|
||||||
{ name: "首页",
|
{
|
||||||
|
name: "首页",
|
||||||
children: [{name: "主页", hash: "#index/index"},
|
children: [{name: "主页", hash: "#index/index"},
|
||||||
{name: "监控", hash: "#monitor/monitor"}]
|
{name: "判题服务器", hash: "#judges/judges"}]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "通用",
|
name: "通用",
|
||||||
@ -49,7 +50,8 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "bootstrap"], function ($,
|
|||||||
];
|
];
|
||||||
|
|
||||||
var adminNav = [
|
var adminNav = [
|
||||||
{ name: "首页",
|
{
|
||||||
|
name: "首页",
|
||||||
children: [{name: "主页", hash: "#index/index"}]
|
children: [{name: "主页", hash: "#index/index"}]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -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("请求失败");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
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);
|
|
||||||
|
|
||||||
});
|
|
@ -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({
|
||||||
|
@ -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"
|
||||||
},
|
},
|
||||||
|
@ -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",
|
||||||
|
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 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)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user