Merge branch 'spj'

* spj:
  SPJ程序warning as error
  增加部分logger配置
  完成对SPJ的支持
  增加测试用例版本号,用于judger重新编译spj程序
  增加admin页面SPJ的帮助链接
  增加比赛题目SPJ的设置
  完善SPJ测试用例的上传
  题目页面增加SPJ标识
  增加编辑题目spj相关的逻辑
  增加Special Judge的基础配置和创建Special Judge题目的逻辑
This commit is contained in:
virusdefender 2016-04-07 16:44:51 +08:00
commit 8325b86ef0
32 changed files with 489 additions and 89 deletions

View File

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.1 on 2016-04-04 07:09
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('contest', '0013_auto_20151017_1511'),
]
operations = [
migrations.AddField(
model_name='contestproblem',
name='spj',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='contestproblem',
name='spj_code',
field=models.TextField(blank=True, null=True),
),
migrations.AddField(
model_name='contestproblem',
name='spj_code_language',
field=models.IntegerField(blank=True, null=True),
),
]

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.1 on 2016-04-04 08:41
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('contest', '0014_auto_20160404_1509'),
]
operations = [
migrations.RenameField(
model_name='contestproblem',
old_name='spj_code_language',
new_name='spj_language',
),
]

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.1 on 2016-04-06 04:20
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('contest', '0015_auto_20160404_1641'),
]
operations = [
migrations.AddField(
model_name='contestproblem',
name='spj_version',
field=models.CharField(blank=True, max_length=32, null=True),
),
]

View File

@ -73,6 +73,9 @@ class CreateContestProblemSerializer(serializers.Serializer):
test_case_id = serializers.CharField(max_length=40) test_case_id = serializers.CharField(max_length=40)
time_limit = serializers.IntegerField() time_limit = serializers.IntegerField()
memory_limit = serializers.IntegerField() memory_limit = serializers.IntegerField()
spj = serializers.BooleanField()
spj_language = serializers.IntegerField(required=False, default=None)
spj_code = serializers.CharField(max_length=10000, required=False, default=None)
hint = serializers.CharField(max_length=3000, allow_blank=True) hint = serializers.CharField(max_length=3000, allow_blank=True)
score = serializers.IntegerField(required=False, default=0) score = serializers.IntegerField(required=False, default=0)
sort_index = serializers.CharField(max_length=30) sort_index = serializers.CharField(max_length=30)
@ -101,6 +104,9 @@ class EditContestProblemSerializer(serializers.Serializer):
test_case_id = serializers.CharField(max_length=40) test_case_id = serializers.CharField(max_length=40)
time_limit = serializers.IntegerField() time_limit = serializers.IntegerField()
memory_limit = serializers.IntegerField() memory_limit = serializers.IntegerField()
spj = serializers.BooleanField()
spj_language = serializers.IntegerField(required=False, default=None)
spj_code = serializers.CharField(max_length=10000, required=False, default=None)
samples = ContestProblemSampleSerializer() samples = ContestProblemSampleSerializer()
hint = serializers.CharField(max_length=3000, allow_blank=True) hint = serializers.CharField(max_length=3000, allow_blank=True)
visible = serializers.BooleanField() visible = serializers.BooleanField()

View File

@ -1,7 +1,8 @@
# coding=utf-8 # coding=utf-8
import json import json
import os
import datetime import datetime
import redis import hashlib
from django.shortcuts import render from django.shortcuts import render
from django.db import IntegrityError from django.db import IntegrityError
@ -176,6 +177,11 @@ class ContestAdminAPIView(APIView):
class ContestProblemAdminAPIView(APIView): class ContestProblemAdminAPIView(APIView):
def _spj_version(self, code):
if code is None:
return None
return hashlib.md5(code.encode("utf-8")).hexdigest()
def post(self, request): def post(self, request):
""" """
比赛题目发布json api接口 比赛题目发布json api接口
@ -202,6 +208,10 @@ class ContestProblemAdminAPIView(APIView):
samples=json.dumps(data["samples"]), samples=json.dumps(data["samples"]),
time_limit=data["time_limit"], time_limit=data["time_limit"],
memory_limit=data["memory_limit"], memory_limit=data["memory_limit"],
spj=data["spj"],
spj_language=data["spj_language"],
spj_code=data["spj_code"],
spj_version=self._spj_version(data["spj_code"]),
created_by=request.user, created_by=request.user,
hint=data["hint"], hint=data["hint"],
contest=contest, contest=contest,
@ -225,6 +235,7 @@ class ContestProblemAdminAPIView(APIView):
contest_problem = ContestProblem.objects.get(id=data["id"]) contest_problem = ContestProblem.objects.get(id=data["id"])
except ContestProblem.DoesNotExist: except ContestProblem.DoesNotExist:
return error_response(u"该比赛题目不存在!") return error_response(u"该比赛题目不存在!")
contest = Contest.objects.get(id=contest_problem.contest_id) contest = Contest.objects.get(id=contest_problem.contest_id)
if request.user.admin_type != SUPER_ADMIN and contest.created_by != request.user: if request.user.admin_type != SUPER_ADMIN and contest.created_by != request.user:
return error_response(u"比赛不存在") return error_response(u"比赛不存在")
@ -235,6 +246,10 @@ class ContestProblemAdminAPIView(APIView):
contest_problem.test_case_id = data["test_case_id"] contest_problem.test_case_id = data["test_case_id"]
contest_problem.time_limit = data["time_limit"] contest_problem.time_limit = data["time_limit"]
contest_problem.memory_limit = data["memory_limit"] contest_problem.memory_limit = data["memory_limit"]
contest_problem.spj = data["spj"]
contest_problem.spj_language = data["spj_language"]
contest_problem.spj_code = data["spj_code"]
contest_problem.spj_version = self._spj_version(data["spj_code"])
contest_problem.samples = json.dumps(data["samples"]) contest_problem.samples = json.dumps(data["samples"])
contest_problem.hint = data["hint"] contest_problem.hint = data["hint"]
contest_problem.visible = data["visible"] contest_problem.visible = data["visible"]

View File

@ -1,12 +1,13 @@
# coding=utf-8 # coding=utf-8
import os import os
import json import json
import commands
import hashlib import hashlib
import judger import judger
import spj_client
from multiprocessing import Pool from multiprocessing import Pool
from settings import max_running_number, lrun_gid, lrun_uid, judger_workspace from settings import max_running_number
from language import languages from language import languages
from result import result from result import result
from judge_exceptions import JudgeClientError from judge_exceptions import JudgeClientError
@ -20,7 +21,7 @@ def _run(instance, test_case_id):
class JudgeClient(object): class JudgeClient(object):
def __init__(self, language_code, exe_path, max_cpu_time, max_memory, test_case_dir, judge_base_path): def __init__(self, language_code, exe_path, max_cpu_time, max_memory, test_case_dir, judge_base_path, spj_path):
""" """
:param language_code: 语言编号 :param language_code: 语言编号
:param exe_path: 可执行文件路径 :param exe_path: 可执行文件路径
@ -53,11 +54,12 @@ class JudgeClient(object):
# 测试用例配置项 # 测试用例配置项
self._test_case_info = self._load_test_case_info() self._test_case_info = self._load_test_case_info()
self._judge_base_path = judge_base_path self._judge_base_path = judge_base_path
self._spj_path = spj_path
def _load_test_case_info(self): def _load_test_case_info(self):
# 读取测试用例信息 转换为dict # 读取测试用例信息 转换为dict
try: try:
f = open(self._test_case_dir + "info") f = open(os.path.join(self._test_case_dir, "info"))
return json.loads(f.read()) return json.loads(f.read())
except IOError: except IOError:
raise JudgeClientError("Test case config file not found") raise JudgeClientError("Test case config file not found")
@ -96,11 +98,13 @@ class JudgeClient(object):
return output_md5, output_md5 == test_case_config["striped_output_md5"] return output_md5, output_md5 == test_case_config["striped_output_md5"]
def _judge_one(self, test_case_id): def _judge_one(self, test_case_id):
in_file = os.path.join(self._test_case_dir, str(test_case_id) + ".in")
out_file = os.path.join(self._judge_base_path, str(test_case_id) + ".out")
run_result = judger.run(path=self.execute_command[0], run_result = judger.run(path=self.execute_command[0],
max_cpu_time=self._max_cpu_time, max_cpu_time=self._max_cpu_time,
max_memory=self._max_memory, max_memory=self._max_memory,
in_file=os.path.join(self._test_case_dir, str(test_case_id) + ".in"), in_file=in_file,
out_file=os.path.join(self._judge_base_path, str(test_case_id) + ".out"), out_file=out_file,
args=self.execute_command[1:], args=self.execute_command[1:],
env=["PATH=" + os.environ["PATH"]], env=["PATH=" + os.environ["PATH"]],
use_sandbox=self._language["use_sandbox"], use_sandbox=self._language["use_sandbox"],
@ -113,12 +117,27 @@ class JudgeClient(object):
# 将judger返回的结果标志转换为本系统中使用的 # 将judger返回的结果标志转换为本系统中使用的
if run_result["flag"] == 0: if run_result["flag"] == 0:
output_md5, r = self._compare_output(test_case_id) if self._spj_path is None:
if r: output_md5, r = self._compare_output(test_case_id)
run_result["result"] = result["accepted"] if r:
run_result["result"] = result["accepted"]
else:
run_result["result"] = result["wrong_answer"]
run_result["output_md5"] = output_md5
else: else:
run_result["result"] = result["wrong_answer"] spj_result = spj_client.spj(path=self._spj_path, max_cpu_time=3 * self._max_cpu_time,
run_result["output_md5"] = output_md5 max_memory=3 * self._max_memory,
in_path=in_file,
user_out_path=out_file)
if spj_result["spj_result"] == spj_client.AC:
run_result["result"] = result["accepted"]
elif spj_result["spj_result"] == spj_client.WA:
run_result["result"] = result["wrong_answer"]
else:
run_result["result"] = result["system_error"]
run_result["error"] = "SPJ Crashed, return: %d, signal: %d" % \
(spj_result["spj_result"], spj_result["signal"])
elif run_result["flag"] in [1, 2]: elif run_result["flag"] in [1, 2]:
run_result["result"] = result["time_limit_exceeded"] run_result["result"] = result["time_limit_exceeded"]
elif run_result["flag"] == 3: elif run_result["flag"] == 3:

View File

@ -1,14 +1,13 @@
# coding=utf-8 # coding=utf-8
import time
import os import os
import judger import judger
from judge_exceptions import CompileError, JudgeClientError from judge_exceptions import CompileError
from logger import logger from logger import logger
from settings import judger_workspace
def compile_(language_item, src_path, exe_path, judge_base_path): def compile_(language_item, src_path, exe_path, judge_base_path, compile_spj=False):
compile_command = language_item["compile_command"].format(src_path=src_path, exe_path=exe_path).split(" ") command_item = "spj_compile_command" if compile_spj else "compile_command"
compile_command = language_item[command_item].format(src_path=src_path, exe_path=exe_path).split(" ")
compiler = compile_command[0] compiler = compile_command[0]
compile_args = compile_command[1:] compile_args = compile_command[1:]
compiler_output_file = os.path.join(judge_base_path, "compiler.out") compiler_output_file = os.path.join(judge_base_path, "compiler.out")

View File

@ -7,6 +7,7 @@ languages = {
"src_name": "main.c", "src_name": "main.c",
"code": 1, "code": 1,
"compile_command": "/usr/bin/gcc -DONLINE_JUDGE -O2 -w -fmax-errors=3 -std=c99 {src_path} -lm -o {exe_path}/main", "compile_command": "/usr/bin/gcc -DONLINE_JUDGE -O2 -w -fmax-errors=3 -std=c99 {src_path} -lm -o {exe_path}/main",
"spj_compile_command": "/usr/bin/gcc -DONLINE_JUDGE -O2 -Werror -fmax-errors=3 -std=c99 {src_path} -lm -o {exe_path}",
"execute_command": "{exe_path}/main", "execute_command": "{exe_path}/main",
"use_sandbox": True "use_sandbox": True
}, },
@ -15,6 +16,7 @@ languages = {
"src_name": "main.cpp", "src_name": "main.cpp",
"code": 2, "code": 2,
"compile_command": "/usr/bin/g++ -DONLINE_JUDGE -O2 -w -fmax-errors=3 -std=c++11 {src_path} -lm -o {exe_path}/main", "compile_command": "/usr/bin/g++ -DONLINE_JUDGE -O2 -w -fmax-errors=3 -std=c++11 {src_path} -lm -o {exe_path}/main",
"spj_compile_command": "/usr/bin/g++ -DONLINE_JUDGE -O2 -Werror -fmax-errors=3 -std=c++11 {src_path} -lm -o {exe_path}",
"execute_command": "{exe_path}/main", "execute_command": "{exe_path}/main",
"use_sandbox": True "use_sandbox": True
}, },

View File

@ -3,6 +3,7 @@ import os
import socket import socket
import shutil import shutil
from logger import logger
from client import JudgeClient from client import JudgeClient
from language import languages from language import languages
from compiler import compile_ from compiler import compile_
@ -12,12 +13,15 @@ from settings import judger_workspace
class JudgeInstanceRunner(object): class JudgeInstanceRunner(object):
def run(self, token, submission_id, language_code, code, time_limit, memory_limit, test_case_id): def run(self, token, submission_id, language_code, code, time_limit, memory_limit, test_case_id,
spj, spj_language, spj_code, spj_version):
language = languages[language_code] language = languages[language_code]
host_name = socket.gethostname() host_name = socket.gethostname()
judge_base_path = os.path.join(judger_workspace, "run", submission_id) judge_base_path = os.path.join(judger_workspace, "run", submission_id)
if not token or token != os.environ.get("rpc_token"): if not token or token != os.environ.get("rpc_token"):
if token:
logger.info("Invalid token: " + token)
return {"code": 2, "data": {"error": "Invalid token", "server": host_name}} return {"code": 2, "data": {"error": "Invalid token", "server": host_name}}
try: try:
@ -35,19 +39,42 @@ class JudgeInstanceRunner(object):
# 编译 # 编译
try: try:
exe_path = compile_(language, src_path, judge_base_path, judge_base_path) exe_path = compile_(language_item=language, src_path=src_path,
exe_path=judge_base_path, judge_base_path=judge_base_path, compile_spj=False)
except Exception as e: except Exception as e:
shutil.rmtree(judge_base_path, ignore_errors=True) shutil.rmtree(judge_base_path, ignore_errors=True)
return {"code": 1, "data": {"error": str(e), "server": host_name}} return {"code": 1, "data": {"error": str(e), "server": host_name}}
test_case_dir = os.path.join(judger_workspace, "test_case", test_case_id)
# SPJ相关
if spj:
spj_path = os.path.join(test_case_dir, "spj-" + spj_version)
if "spj-" + spj_version not in os.listdir(test_case_dir):
spj_language_item = languages[spj_language]
spj_code_path = os.path.join(test_case_dir, "spj-" + spj_language_item["src_name"])
f = open(spj_code_path, "w")
f.write(spj_code.encode("utf8"))
f.close()
try:
compile_(language_item=languages[spj_language], src_path=spj_code_path,
exe_path=spj_path,
judge_base_path=judge_base_path, compile_spj=True)
except Exception as e:
return {"code": 2, "data": {"error": "SPJ Compile error: " + str(e), "server": host_name}}
else:
spj_path = None
# 运行 # 运行
try: try:
client = JudgeClient(language_code=language_code, client = JudgeClient(language_code=language_code,
exe_path=exe_path, exe_path=exe_path,
max_cpu_time=int(time_limit), max_cpu_time=int(time_limit),
max_memory=int(memory_limit) * 1024 * 1024, max_memory=int(memory_limit) * 1024 * 1024,
test_case_dir=judger_workspace + "test_case/" + test_case_id + "/", test_case_dir=test_case_dir,
judge_base_path=judge_base_path) judge_base_path=judge_base_path, spj_path=spj_path)
judge_result = {"result": result["accepted"], "info": client.run(), judge_result = {"result": result["accepted"], "info": client.run(),
"accepted_answer_time": None, "server": host_name} "accepted_answer_time": None, "server": host_name}

View File

@ -1,16 +1,9 @@
# coding=utf-8 # coding=utf-8
import os
# 单个判题端最多同时运行的程序个数因为判题端会同时运行多组测试数据比如一共有5组测试数据 # 单个判题端最多同时运行的程序个数因为判题端会同时运行多组测试数据比如一共有5组测试数据
# 如果MAX_RUNNING_NUMBER大于等于5那么这5组数据就会同时进行评测然后返回结果。 # 如果MAX_RUNNING_NUMBER大于等于5那么这5组数据就会同时进行评测然后返回结果。
# 如果MAX_RUNNING_NUMBER小于5为3那么就会同时运行前三组测试数据然后再运行后两组数据 # 如果MAX_RUNNING_NUMBER小于5为3那么就会同时运行前三组测试数据然后再运行后两组数据
# 这样可以避免同时运行的程序过多导致的cpu占用太高 # 这样可以避免同时运行的程序过多导致的cpu占用太高
max_running_number = 10 max_running_number = 10
# lrun运行用户的uid
lrun_uid = 1001
# lrun用户组gid
lrun_gid = 1002
# judger工作目录 # judger工作目录
judger_workspace = "/var/judger/" judger_workspace = "/var/judger/"

26
judge/spj_client.py Normal file
View File

@ -0,0 +1,26 @@
# coding=utf-8
import os
import judger
WA = 1
AC = 0
SPJ_ERROR = -1
def file_exists(path):
return os.path.exists(path)
def spj(path, max_cpu_time, max_memory, in_path, user_out_path):
if file_exists(in_path) and file_exists(user_out_path):
result = judger.run(path=path, in_file="/dev/null", out_file="/dev/null",
max_cpu_time=max_cpu_time, max_memory=max_memory,
args=[in_path, user_out_path], env=["PATH=" + os.environ.get("PATH", "")],
use_sandbox=True, use_nobody=True)
if result["signal"] == 0 and result["exit_status"] in [AC, WA, SPJ_ERROR]:
result["spj_result"] = result["exit_status"]
else:
result["spj_result"] = SPJ_ERROR
return result
else:
raise ValueError("in_path or user_out_path does not exist")

View File

@ -41,6 +41,10 @@ class JudgeWaitingQueue(models.Model):
memory_limit = models.IntegerField() memory_limit = models.IntegerField()
test_case_id = models.CharField(max_length=40) test_case_id = models.CharField(max_length=40)
create_time = models.DateTimeField(auto_now_add=True) create_time = models.DateTimeField(auto_now_add=True)
spj = models.BooleanField(default=False)
spj_language = models.IntegerField(blank=True, null=True)
spj_code = models.TextField(blank=True, null=True)
spj_version = models.CharField(max_length=32, blank=True, null=True)
class Meta: class Meta:
db_table = "judge_waiting_queue" db_table = "judge_waiting_queue"

View File

@ -20,12 +20,23 @@ logger = logging.getLogger("app_info")
class JudgeDispatcher(object): class JudgeDispatcher(object):
def __init__(self, submission, time_limit, memory_limit, test_case_id): def _none_to_false(self, value):
self.submission = submission # xml rpc不能使用None
if value is None:
return False
else:
return value
def __init__(self, submission_id, time_limit, memory_limit, test_case_id, spj, spj_language, spj_code, spj_version):
self.submission = Submission.objects.get(id=submission_id)
self.time_limit = time_limit self.time_limit = time_limit
self.memory_limit = memory_limit self.memory_limit = memory_limit
self.test_case_id = test_case_id self.test_case_id = test_case_id
self.user = User.objects.get(id=submission.user_id) self.user = User.objects.get(id=self.submission.user_id)
self.spj = spj
self.spj_language = spj_language
self.spj_code = spj_code
self.spj_version = spj_version
def choose_judge_server(self): def choose_judge_server(self):
servers = JudgeServer.objects.filter(workload__lt=100, lock=False, status=True).order_by("-workload") servers = JudgeServer.objects.filter(workload__lt=100, lock=False, status=True).order_by("-workload")
@ -41,16 +52,21 @@ class JudgeDispatcher(object):
# 如果没有合适的判题服务器,就放入等待队列中等待判题 # 如果没有合适的判题服务器,就放入等待队列中等待判题
if not judge_server: if not judge_server:
JudgeWaitingQueue.objects.create(submission_id=self.submission.id, time_limit=self.time_limit, JudgeWaitingQueue.objects.create(submission_id=self.submission.id, time_limit=self.time_limit,
memory_limit=self.memory_limit, test_case_id=self.test_case_id) memory_limit=self.memory_limit, test_case_id=self.test_case_id,
spj=self.spj, spj_language=self.spj_language, spj_code=self.spj_code,
spj_version=self.spj_version)
return return
judge_server.use_judge_instance() judge_server.use_judge_instance()
try: try:
s = TimeoutServerProxy("http://" + judge_server.ip + ":" + str(judge_server.port), timeout=20) s = TimeoutServerProxy("http://" + judge_server.ip + ":" + str(judge_server.port),
timeout=30)
data = s.run(judge_server.token, self.submission.id, self.submission.language, data = s.run(judge_server.token, self.submission.id, self.submission.language,
self.submission.code, self.time_limit, self.memory_limit, self.test_case_id) self.submission.code, self.time_limit, self.memory_limit, self.test_case_id,
self.spj, self._none_to_false(self.spj_language),
self._none_to_false(self.spj_code), self._none_to_false(self.spj_version))
# 编译错误 # 编译错误
if data["code"] == 1: if data["code"] == 1:
self.submission.result = result["compile_error"] self.submission.result = result["compile_error"]
@ -71,7 +87,7 @@ class JudgeDispatcher(object):
judge_server.release_judge_instance() judge_server.release_judge_instance()
self.submission.judge_end_time = int(time.time() * 1000) self.submission.judge_end_time = int(time.time() * 1000)
self.submission.save() self.submission.save(update_fields=["judge_start_time", "result", "info", "accepted_answer_time", "judge_end_time"])
if self.submission.contest_id: if self.submission.contest_id:
self.update_contest_problem_status() self.update_contest_problem_status()
@ -85,13 +101,15 @@ class JudgeDispatcher(object):
from submission.tasks import _judge from submission.tasks import _judge
waiting_submission = waiting_submissions.first() waiting_submission = waiting_submissions.first()
submission = Submission.objects.get(id=waiting_submission.submission_id)
waiting_submission.delete() waiting_submission.delete()
_judge.delay(submission_id=waiting_submission.submission_id,
_judge.delay(submission=submission, time_limit=waiting_submission.time_limit, time_limit=waiting_submission.time_limit,
memory_limit=waiting_submission.memory_limit, memory_limit=waiting_submission.memory_limit,
test_case_id=waiting_submission.test_case_id) test_case_id=waiting_submission.test_case_id,
spj=waiting_submission.spj,
spj_language=waiting_submission.spj_language,
spj_code=waiting_submission.spj_code,
spj_version=waiting_submission.spj_version)
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)

View File

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.1 on 2016-04-04 07:09
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('problem', '0011_auto_20151017_1227'),
]
operations = [
migrations.AddField(
model_name='problem',
name='spj',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='problem',
name='spj_code',
field=models.TextField(blank=True, null=True),
),
migrations.AddField(
model_name='problem',
name='spj_code_language',
field=models.IntegerField(blank=True, null=True),
),
]

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.1 on 2016-04-04 08:41
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('problem', '0012_auto_20160404_1509'),
]
operations = [
migrations.RenameField(
model_name='problem',
old_name='spj_code_language',
new_name='spj_language',
),
]

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.1 on 2016-04-06 04:20
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('problem', '0013_auto_20160404_1641'),
]
operations = [
migrations.AddField(
model_name='problem',
name='spj_version',
field=models.CharField(blank=True, max_length=32, null=True),
),
]

View File

@ -38,6 +38,11 @@ class AbstractProblem(models.Model):
time_limit = models.IntegerField() time_limit = models.IntegerField()
# 内存限制 单位是MB # 内存限制 单位是MB
memory_limit = models.IntegerField() memory_limit = models.IntegerField()
# special judge
spj = models.BooleanField(default=False)
spj_language = models.IntegerField(blank=True, null=True)
spj_code = models.TextField(blank=True, null=True)
spj_version = models.CharField(max_length=32, blank=True, null=True)
# 是否可见 false的话相当于删除 # 是否可见 false的话相当于删除
visible = models.BooleanField(default=True) visible = models.BooleanField(default=True)
# 总共提交数量 # 总共提交数量

View File

@ -27,6 +27,9 @@ class CreateProblemSerializer(serializers.Serializer):
test_case_id = serializers.CharField(max_length=40) test_case_id = serializers.CharField(max_length=40)
time_limit = serializers.IntegerField(min_value=1, max_value=10000) time_limit = serializers.IntegerField(min_value=1, max_value=10000)
memory_limit = serializers.IntegerField(min_value=16) memory_limit = serializers.IntegerField(min_value=16)
spj = serializers.BooleanField()
spj_language = serializers.IntegerField(required=False, default=None)
spj_code = serializers.CharField(max_length=10000, required=False, default=None)
difficulty = serializers.IntegerField() difficulty = serializers.IntegerField()
tags = serializers.ListField(child=serializers.CharField(max_length=10)) tags = serializers.ListField(child=serializers.CharField(max_length=10))
hint = serializers.CharField(max_length=3000, allow_blank=True) hint = serializers.CharField(max_length=3000, allow_blank=True)
@ -73,6 +76,9 @@ class EditProblemSerializer(serializers.Serializer):
source = serializers.CharField(max_length=100) source = serializers.CharField(max_length=100)
time_limit = serializers.IntegerField(min_value=1) time_limit = serializers.IntegerField(min_value=1)
memory_limit = serializers.IntegerField(min_value=1) memory_limit = serializers.IntegerField(min_value=1)
spj = serializers.BooleanField()
spj_language = serializers.IntegerField(required=False, default=None)
spj_code = serializers.CharField(max_length=10000, required=False, default=None)
difficulty = serializers.IntegerField() difficulty = serializers.IntegerField()
tags = serializers.ListField(child=serializers.CharField(max_length=20)) tags = serializers.ListField(child=serializers.CharField(max_length=20))
samples = ProblemSampleSerializer() samples = ProblemSampleSerializer()

View File

@ -66,6 +66,11 @@ class ProblemTagAdminAPIView(APIView):
class ProblemAdminAPIView(APIView): class ProblemAdminAPIView(APIView):
def _spj_version(self, code):
if code is None:
return None
return hashlib.md5(code.encode("utf-8")).hexdigest()
@super_admin_required @super_admin_required
def post(self, request): def post(self, request):
""" """
@ -91,6 +96,10 @@ class ProblemAdminAPIView(APIView):
samples=json.dumps(data["samples"]), samples=json.dumps(data["samples"]),
time_limit=data["time_limit"], time_limit=data["time_limit"],
memory_limit=data["memory_limit"], memory_limit=data["memory_limit"],
spj=data["spj"],
spj_language=data["spj_language"],
spj_code=data["spj_code"],
spj_version=self._spj_version(data["spj_code"]),
difficulty=data["difficulty"], difficulty=data["difficulty"],
created_by=request.user, created_by=request.user,
hint=data["hint"], hint=data["hint"],
@ -117,6 +126,7 @@ class ProblemAdminAPIView(APIView):
if serializer.is_valid(): if serializer.is_valid():
data = serializer.data data = serializer.data
problem = Problem.objects.get(id=data["id"]) problem = Problem.objects.get(id=data["id"])
problem.title = data["title"] problem.title = data["title"]
problem.description = data["description"] problem.description = data["description"]
problem.input_description = data["input_description"] problem.input_description = data["input_description"]
@ -125,6 +135,10 @@ class ProblemAdminAPIView(APIView):
problem.source = data["source"] problem.source = data["source"]
problem.time_limit = data["time_limit"] problem.time_limit = data["time_limit"]
problem.memory_limit = data["memory_limit"] problem.memory_limit = data["memory_limit"]
problem.spj = data["spj"]
problem.spj_language = data["spj_language"]
problem.spj_code = data["spj_code"]
problem.spj_version = self._spj_version(data["spj_code"])
problem.difficulty = data["difficulty"] problem.difficulty = data["difficulty"]
problem.samples = json.dumps(data["samples"]) problem.samples = json.dumps(data["samples"])
problem.hint = data["hint"] problem.hint = data["hint"]
@ -140,7 +154,9 @@ class ProblemAdminAPIView(APIView):
except ProblemTag.DoesNotExist: except ProblemTag.DoesNotExist:
tag = ProblemTag.objects.create(name=tag) tag = ProblemTag.objects.create(name=tag)
problem.tags.add(tag) problem.tags.add(tag)
problem.save() problem.save()
return success_response(ProblemSerializer(problem).data) return success_response(ProblemSerializer(problem).data)
else: else:
return serializer_invalid_response(serializer) return serializer_invalid_response(serializer)
@ -214,72 +230,104 @@ class TestCaseUploadAPIView(APIView):
if len(name_list) == 0: if len(name_list) == 0:
return error_response(u"压缩包内没有文件") return error_response(u"压缩包内没有文件")
if len(name_list) % 2 == 1: for item in name_list:
return error_response(u"测试用例文件格式错误,文件数目为奇数") if not self._is_legal_test_case_file_name(item):
return error_response(u"%s 文件名不符合规范" % item)
for index in range(1, len(name_list) / 2 + 1): # 排序,这样name_list就是[1.in, 1.out, 2.in, 2.out]的形式了
if not (str(index) + ".in" in name_list and str(index) + ".out" in name_list): name_list.sort()
return error_response(u"测试用例文件格式错误,缺少" + str(index) + u".in/.out文件")
spj = False
for item in name_list:
# 代表里面有.out文件,所以应该是普通题目的测试用例
if item.endswith(".out"):
break
else:
# 否则就应该是spj的测试用例
spj = True
if not spj:
if len(name_list) % 2 == 1:
return error_response(u"测试用例文件格式错误,文件数目为奇数")
for index in range(1, len(name_list) / 2 + 1):
if not (str(index) + ".in" in name_list and str(index) + ".out" in name_list):
return error_response(u"测试用例文件格式错误,缺少" + str(index) + u".in/.out文件")
test_case_number = len(name_list) / 2
else:
for index in range(1, len(name_list) + 1):
if str(index) + ".in" not in name_list:
return error_response(u"测试用例文件格式错误,缺少" + str(index) + u".in文件")
test_case_number = len(name_list)
problem_test_dir = rand_str() problem_test_dir = rand_str()
test_case_dir = settings.TEST_CASE_DIR + problem_test_dir + "/" test_case_dir = os.path.join(settings.TEST_CASE_DIR, problem_test_dir)
# 得到了合法的测试用例文件列表 然后去解压缩 # 得到了合法的测试用例文件列表 然后去解压缩
os.mkdir(test_case_dir) os.mkdir(test_case_dir)
for name in name_list: for name in name_list:
f = open(test_case_dir + name, "wb") f = open(os.path.join(test_case_dir, name), "wb")
try: try:
f.write(test_case_file.read(name).replace("\r\n", "\n")) f.write(test_case_file.read(name).replace("\r\n", "\n"))
except MemoryError: except MemoryError:
return error_response(u"单个测试数据体积过大!") return error_response(u"单个测试数据体积过大!")
finally: finally:
f.close() f.close()
name_list.sort()
file_info = {"test_case_number": len(name_list) / 2, "test_cases": {}} file_info = {"test_case_number": test_case_number, "test_cases": {}, "spj": spj}
# 计算输出文件的md5 # 计算输出文件的md5
for i in range(1, len(name_list) / 2 + 1): for i in range(1, test_case_number + 1):
md5 = hashlib.md5() if not spj:
striped_md5 = hashlib.md5() md5 = hashlib.md5()
f = open(test_case_dir + str(i) + ".out", "r") striped_md5 = hashlib.md5()
# 完整文件的md5 f = open(os.path.join(test_case_dir, str(i) + ".out"), "r")
while True: # 完整文件的md5
data = f.read(2 ** 8) while True:
if not data: data = f.read(2 ** 8)
break if not data:
md5.update(data) break
md5.update(data)
# 删除标准输出最后的空格和换行 # 删除标准输出最后的空格和换行
# 这时只能一次全部读入了,分块读的话,没办法确定文件结尾 # 这时只能一次全部读入了,分块读的话,没办法确定文件结尾
f.seek(0) f.seek(0)
striped_md5.update(f.read().rstrip()) striped_md5.update(f.read().rstrip())
output_md5 = md5.hexdigest()
striped_output_md5 = striped_md5.hexdigest()
output_name = str(i) + ".out"
output_size = os.path.getsize(os.path.join(test_case_dir, output_name))
else:
output_md5 = striped_output_md5 = output_name = output_size = None
file_info["test_cases"][str(i)] = {"input_name": str(i) + ".in", file_info["test_cases"][str(i)] = {"input_name": str(i) + ".in",
"output_name": str(i) + ".out", "output_name": output_name,
"output_md5": md5.hexdigest(), "output_md5": output_md5,
"striped_output_md5": striped_md5.hexdigest(), "striped_output_md5": striped_output_md5,
"input_size": os.path.getsize(test_case_dir + str(i) + ".in"), "input_size": os.path.getsize(os.path.join(test_case_dir, str(i) + ".in")),
"output_size": os.path.getsize(test_case_dir + str(i) + ".out")} "output_size": output_size}
# 写入配置文件 # 写入配置文件
with open(test_case_dir + "info", "w") as f: with open(os.path.join(test_case_dir, "info"), "w") as f:
f.write(json.dumps(file_info)) f.write(json.dumps(file_info))
return success_response({"test_case_id": problem_test_dir, return success_response({"test_case_id": problem_test_dir,
"file_list": file_info["test_cases"]}) "file_list": file_info["test_cases"],
"spj": spj})
def get(self, request): def get(self, request):
test_case_id = request.GET.get("test_case_id", None) test_case_id = request.GET.get("test_case_id", None)
if not test_case_id: if not test_case_id:
return error_response(u"参数错误") return error_response(u"参数错误")
test_case_config = settings.TEST_CASE_DIR + test_case_id + "/info" test_case_config = os.path.join(settings.TEST_CASE_DIR, test_case_id, "info")
try: try:
f = open(test_case_config) f = open(test_case_config)
config = json.loads(f.read()) config = json.loads(f.read())
f.close() f.close()
except Exception as e: except Exception as e:
return error_response(u"读取测试用例出错") return error_response(u"读取测试用例出错")
return success_response({"file_list": config["test_cases"]}) return success_response({"file_list": config["test_cases"], "spj": config.get("spj", False)})
def problem_list_page(request, page=1): def problem_list_page(request, page=1):

View File

@ -1,5 +1,5 @@
require(["jquery", "avalon", "editor", "uploader", "bsAlert", require(["jquery", "avalon", "editor", "uploader", "bsAlert",
"csrfToken", "tagEditor", "validator", "editorComponent", "testCaseUploader"], "csrfToken", "tagEditor", "validator", "editorComponent", "testCaseUploader", "spj"],
function ($, avalon, editor, uploader, bsAlert, csrfTokenHeader) { function ($, avalon, editor, uploader, bsAlert, csrfTokenHeader) {
avalon.ready(function () { avalon.ready(function () {
@ -34,6 +34,11 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert",
return false; return false;
} }
} }
var spjVM = avalon.vmodels.spjConfig;
if (spjVM.spj && !spjVM.spjCode){
bsAlert("请填写Special Judge的代码");
return false;
}
var ajaxData = { var ajaxData = {
title: vm.title, title: vm.title,
description: avalon.vmodels.contestProblemDescriptionEditor.content, description: avalon.vmodels.contestProblemDescriptionEditor.content,
@ -46,8 +51,13 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert",
contest_id: avalon.vmodels.admin.contestId, contest_id: avalon.vmodels.admin.contestId,
input_description: vm.inputDescription, input_description: vm.inputDescription,
output_description: vm.outputDescription, output_description: vm.outputDescription,
sort_index: vm.sortIndex sort_index: vm.sortIndex,
spj: spjVM.spj
}; };
if (spjVM.spj) {
ajaxData.spj_language = spjVM.spjLanguage;
ajaxData.spj_code = spjVM.spjCode;
}
if (avalon.vmodels.admin.contestProblemStatus == "edit") { if (avalon.vmodels.admin.contestProblemStatus == "edit") {
var method = "put"; var method = "put";
@ -185,6 +195,11 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert",
}) })
} }
avalon.vmodels.contestProblemHintEditor.content = problem.hint; avalon.vmodels.contestProblemHintEditor.content = problem.hint;
var spjVM = avalon.vmodels.spjConfig;
spjVM.spj = problem.spj;
// spjLanguage可能是null
spjVM.spjLanguage = problem.spj_language=="2"?"2":"1";
spjVM.spjCode = problem.spj_code;
} }
} }
}); });

View File

@ -1,5 +1,5 @@
require(["jquery", "avalon", "editor", "uploader", "bsAlert", require(["jquery", "avalon", "editor", "uploader", "bsAlert",
"csrfToken", "tagEditor", "validator", "jqueryUI", "editorComponent", "testCaseUploader"], "csrfToken", "tagEditor", "validator", "jqueryUI", "editorComponent", "testCaseUploader", "spj"],
function ($, avalon, editor, uploader, bsAlert, csrfTokenHeader) { function ($, avalon, editor, uploader, bsAlert, csrfTokenHeader) {
avalon.ready(function () { avalon.ready(function () {
@ -37,6 +37,11 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert",
bsAlert("请至少添加一个标签,这将有利于用户发现你的题目!"); bsAlert("请至少添加一个标签,这将有利于用户发现你的题目!");
return false; return false;
} }
var spjVM = avalon.vmodels.spjConfig;
if (spjVM.spj && !spjVM.spjCode){
bsAlert("请填写Special Judge的代码");
return false;
}
var ajaxData = { var ajaxData = {
id: avalon.vmodels.admin.problemId, id: avalon.vmodels.admin.problemId,
title: vm.title, title: vm.title,
@ -51,8 +56,13 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert",
tags: tags, tags: tags,
input_description: vm.inputDescription, input_description: vm.inputDescription,
output_description: vm.outputDescription, output_description: vm.outputDescription,
difficulty: vm.difficulty difficulty: vm.difficulty,
spj: spjVM.spj
}; };
if (spjVM.spj) {
ajaxData.spj_language = spjVM.spjLanguage;
ajaxData.spj_code = spjVM.spjCode;
}
for (var i = 0; i < vm.samples.$model.length; i++) { for (var i = 0; i < vm.samples.$model.length; i++) {
ajaxData.samples.push({ ajaxData.samples.push({
@ -99,7 +109,7 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert",
vm.source = ""; vm.source = "";
vm.uploadProgress = 0; vm.uploadProgress = 0;
} }
else else {
var vm = avalon.define({ var vm = avalon.define({
$id: "addProblem", $id: "addProblem",
title: "", title: "",
@ -143,6 +153,7 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert",
return "展开"; return "展开";
} }
}); });
}
var tagAutoCompleteList = []; var tagAutoCompleteList = [];

View File

@ -1,5 +1,5 @@
require(["jquery", "avalon", "editor", "uploader", "bsAlert", require(["jquery", "avalon", "editor", "uploader", "bsAlert",
"csrfToken", "tagEditor", "validator", "jqueryUI", "editorComponent", "testCaseUploader"], "csrfToken", "tagEditor", "validator", "jqueryUI", "editorComponent", "testCaseUploader", "spj"],
function ($, avalon, editor, uploader, bsAlert, csrfTokenHeader) { function ($, avalon, editor, uploader, bsAlert, csrfTokenHeader) {
avalon.ready(function () { avalon.ready(function () {
@ -38,6 +38,11 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert",
bsAlert("请至少添加一个标签,这将有利于用户发现你的题目!"); bsAlert("请至少添加一个标签,这将有利于用户发现你的题目!");
return false; return false;
} }
var spjVM = avalon.vmodels.spjConfig;
if (spjVM.spj && !spjVM.spjCode){
bsAlert("请填写Special Judge的代码");
return false;
}
var ajaxData = { var ajaxData = {
id: avalon.vmodels.admin.problemId, id: avalon.vmodels.admin.problemId,
title: vm.title, title: vm.title,
@ -52,8 +57,13 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert",
tags: tags, tags: tags,
input_description: vm.inputDescription, input_description: vm.inputDescription,
output_description: vm.outputDescription, output_description: vm.outputDescription,
difficulty: vm.difficulty difficulty: vm.difficulty,
spj: spjVM.spj
}; };
if (spjVM.spj) {
ajaxData.spj_language = spjVM.spjLanguage;
ajaxData.spj_code = spjVM.spjCode;
}
for (var i = 0; i < vm.samples.$model.length; i++) { for (var i = 0; i < vm.samples.$model.length; i++) {
ajaxData.samples.push({ ajaxData.samples.push({
@ -86,7 +96,7 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert",
if (avalon.vmodels.editProblem) { if (avalon.vmodels.editProblem) {
var vm = avalon.vmodels.editProblem; var vm = avalon.vmodels.editProblem;
} }
else else {
var vm = avalon.define({ var vm = avalon.define({
$id: "editProblem", $id: "editProblem",
title: "", title: "",
@ -132,6 +142,7 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert",
avalon.vmodels.admin.template_url = "template/problem/problem_list.html"; avalon.vmodels.admin.template_url = "template/problem/problem_list.html";
} }
}); });
}
$.ajax({ $.ajax({
url: "/api/admin/problem/?problem_id=" + avalon.vmodels.admin.problemId, url: "/api/admin/problem/?problem_id=" + avalon.vmodels.admin.problemId,
@ -161,6 +172,12 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert",
vm.inputDescription = problem.input_description; vm.inputDescription = problem.input_description;
vm.outputDescription = problem.output_description; vm.outputDescription = problem.output_description;
avalon.vmodels.testCaseUploader.setTestCase(problem.test_case_id); avalon.vmodels.testCaseUploader.setTestCase(problem.test_case_id);
var spjVM = avalon.vmodels.spjConfig;
spjVM.spj = problem.spj;
// spjLanguage可能是null
spjVM.spjLanguage = problem.spj_language=="2"?"2":"1";
spjVM.spjCode = problem.spj_code;
vm.source = problem.source; vm.source = problem.source;
var problemTags = problem.tags; var problemTags = problem.tags;
$.ajax({ $.ajax({

View File

@ -27,6 +27,7 @@
pager: "components/pager", pager: "components/pager",
editorComponent: "components/editorComponent", editorComponent: "components/editorComponent",
testCaseUploader: "components/testCaseUploader", testCaseUploader: "components/testCaseUploader",
spj: "components/spj",
// ------ 下面写的都不要直接用,而是使用上面的封装版本 ------ // ------ 下面写的都不要直接用,而是使用上面的封装版本 ------
//富文本编辑器simditor -> editor //富文本编辑器simditor -> editor

View File

@ -0,0 +1,38 @@
define("spj", ["avalon", "bsAlert"], function (avalon, bsAlert) {
avalon.component("ms:spj", {
$template: '<div class="col-md-6">' +
'<label>Special Judge</label>' +
'<div class="form-group">' +
'<label class="text"><input type="checkbox" ms-duplex-checked="spj" ms-attr-disabled="checkboxDisabled">' +
'<small> Special Judge用于答案不唯一的情况,需要自己上传判题代码。上传测试用后如需要修改, 必须重新上传对应类型的新测试用例。' +
'<a href="https://github.com/QingdaoU/OnlineJudge/wiki/SpecialJudge" target="_blank">帮助和示例</a></small>' +
'</label></div></div>' +
'<div class="col-md-6" ms-if="spj">' +
'<label>SPJ代码语言</label>' +
'<div class="form-group">' +
'<label class="text">' +
'<input type="radio" name="spjLanguage" value="1" ms-duplex-string="spjLanguage"> C ' +
'<input type="radio" name="spjLanguage" value="2" ms-duplex-string="spjLanguage"> C++' +
'</label>' +
'</div>' +
'</div>' +
'<div class="col-md-12" ms-if="spj">' +
'<label>SPJ代码</label>' +
'<textarea class="form-control" rows="5" ms-duplex="spjCode"></textarea>' +
'</div>',
spj: false,
spjLanguage: 1,
spjCode: "",
checkboxDisabled: false,
$init: function(vm, el) {
vm.$watch("testCaseUploadFinished", function (spj) {
vm.spj = spj;
vm.checkboxDisabled = true;
});
},
$ready: function (vm, el) {
el.msRetain = true;
}
})
});

View File

@ -7,7 +7,7 @@ define("testCaseUploader", ["avalon", "uploader", "bsAlert", "jquery"], function
'请将所有测试用例打包在一个文件中上传,' + '请将所有测试用例打包在一个文件中上传,' +
'所有文件要在压缩包的根目录,' + '所有文件要在压缩包的根目录,' +
'且输入输出文件名要以从1开始连续数字标识要对应例如' + '且输入输出文件名要以从1开始连续数字标识要对应例如' +
'<br>1.in 1.out 2.in 2.out </small> ' + '<br>1.in 1.out 2.in 2.out(普通题目)或者1.in 2.in 3.in(Special Judge) </small> ' +
'<p>上传进度<span ms-text="uploadProgress"></span>%</p> ' + '<p>上传进度<span ms-text="uploadProgress"></span>%</p> ' +
'<table class="table table-striped" ms-visible="uploaded"> ' + '<table class="table table-striped" ms-visible="uploaded"> ' +
'<tr> <td>编号</td> <td>输入文件名</td> <td>输出文件名</td> </tr> ' + '<tr> <td>编号</td> <td>输入文件名</td> <td>输出文件名</td> </tr> ' +
@ -48,6 +48,7 @@ define("testCaseUploader", ["avalon", "uploader", "bsAlert", "jquery"], function
} }
vm.uploaded = true; vm.uploaded = true;
vm.uploadProgress = 100; vm.uploadProgress = 100;
vm.$fire("all!testCaseUploadFinished", data.data.spj);
} }
} }
}); });
@ -72,7 +73,7 @@ define("testCaseUploader", ["avalon", "uploader", "bsAlert", "jquery"], function
output: response.data.file_list[key].output_name output: response.data.file_list[key].output_name
}) })
} }
bsAlert("测试数据添加成功!共添加" + vm.testCaseList.length + "组测试数据"); vm.$fire("all!testCaseUploadFinished", response.data.spj);
} }
}, },
function (file, percentage) { function (file, percentage) {

View File

@ -28,6 +28,7 @@ var require = {
pager: "components/pager", pager: "components/pager",
editorComponent: "components/editorComponent", editorComponent: "components/editorComponent",
testCaseUploader: "components/testCaseUploader", testCaseUploader: "components/testCaseUploader",
spj: "components/spj",
// ------ 下面写的都不要直接用,而是使用上面的封装版本 ------ // ------ 下面写的都不要直接用,而是使用上面的封装版本 ------

View File

@ -5,5 +5,5 @@ from judge_dispatcher.tasks import JudgeDispatcher
@shared_task @shared_task
def _judge(submission, time_limit, memory_limit, test_case_id): def _judge(submission_id, time_limit, memory_limit, test_case_id, spj=False, spj_language=None, spj_code=None, spj_version=None):
JudgeDispatcher(submission, time_limit, memory_limit, test_case_id).judge() JudgeDispatcher(submission_id, time_limit, memory_limit, test_case_id, spj, spj_language, spj_code, spj_version).judge()

View File

@ -53,7 +53,8 @@ def _submit_code(user, problem_id, language, code):
problem_id=problem.id) problem_id=problem.id)
try: try:
_judge.delay(submission, problem.time_limit, problem.memory_limit, problem.test_case_id) _judge.delay(submission.id, problem.time_limit, problem.memory_limit, problem.test_case_id,
problem.spj, problem.spj_language, problem.spj_code, problem.spj_version)
except Exception as e: except Exception as e:
logger.error(e) logger.error(e)
return error_response(u"提交判题任务失败") return error_response(u"提交判题任务失败")
@ -147,7 +148,8 @@ class ContestSubmissionAPIView(APIView):
code=data["code"], code=data["code"],
problem_id=problem.id) problem_id=problem.id)
try: try:
_judge.delay(submission, problem.time_limit, problem.memory_limit, problem.test_case_id) _judge.delay(submission.id, problem.time_limit, problem.memory_limit, problem.test_case_id,
problem.spj. problem.spj_language, problem.spj_code, problem.spj_version)
except Exception as e: except Exception as e:
logger.error(e) logger.error(e)
return error_response(u"提交判题任务失败") return error_response(u"提交判题任务失败")
@ -332,7 +334,8 @@ class SubmissionRejudgeAdminAPIView(APIView):
except Problem.DoesNotExist: except Problem.DoesNotExist:
return error_response(u"题目不存在") return error_response(u"题目不存在")
try: try:
_judge.delay(submission, problem.time_limit, problem.memory_limit, problem.test_case_id) _judge.delay(submission.id, problem.time_limit, problem.memory_limit, problem.test_case_id,
problem.spj. problem.spj_language, problem.spj_code, problem.spj_version)
except Exception as e: except Exception as e:
logger.error(e) logger.error(e)
return error_response(u"提交判题任务失败") return error_response(u"提交判题任务失败")

View File

@ -96,6 +96,7 @@
</div> </div>
</div> </div>
</div> </div>
<ms:spj $id="spjConfig"></ms:spj>
<ms:testcaseuploader $id="testCaseUploader"></ms:testcaseuploader> <ms:testcaseuploader $id="testCaseUploader"></ms:testcaseuploader>
<div class="form-group col-md-12"> <div class="form-group col-md-12">
<label>提示</label> <label>提示</label>

View File

@ -13,7 +13,6 @@
<ms:editor $id="problemDescriptionEditor" config="problemDescriptionEditor"></ms:editor> <ms:editor $id="problemDescriptionEditor" config="problemDescriptionEditor"></ms:editor>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<div class="form-group"><label>时间限制(ms, 范围1-10000ms)</label> <div class="form-group"><label>时间限制(ms, 范围1-10000ms)</label>
<input type="number" name="timeLimit" class="form-control" ms-duplex="timeLimit" <input type="number" name="timeLimit" class="form-control" ms-duplex="timeLimit"
@ -99,6 +98,7 @@
</div> </div>
</div> </div>
</div> </div>
<ms:spj $id="spjConfig"></ms:spj>
<ms:testcaseuploader $id="testCaseUploader"></ms:testcaseuploader> <ms:testcaseuploader $id="testCaseUploader"></ms:testcaseuploader>
<div class="form-group col-md-12"> <div class="form-group col-md-12">
<label>提示</label> <label>提示</label>

View File

@ -105,6 +105,7 @@
</div> </div>
</div> </div>
</div> </div>
<ms:spj $id="spjConfig"></ms:spj>
<ms:testcaseuploader $id="testCaseUploader"></ms:testcaseuploader> <ms:testcaseuploader $id="testCaseUploader"></ms:testcaseuploader>
<div class="form-group col-md-12"> <div class="form-group col-md-12">
<label>提示</label> <label>提示</label>

View File

@ -5,4 +5,7 @@
{% if problem.last_update_time %}最后更新: {{ problem.last_update_time }}&nbsp;&nbsp;{% endif %} {% if problem.last_update_time %}最后更新: {{ problem.last_update_time }}&nbsp;&nbsp;{% endif %}
时间限制: {{ problem.time_limit }}ms&nbsp;&nbsp; 时间限制: {{ problem.time_limit }}ms&nbsp;&nbsp;
内存限制: {{ problem.memory_limit }}M 内存限制: {{ problem.memory_limit }}M
{% if problem.spj %}
&nbsp;&nbsp;<span class="label label-info">SPJ</span>
{% endif %}
</p> </p>