添加SPJ编译API

This commit is contained in:
zema1 2017-11-16 22:12:17 +08:00
parent 7d1f9452cf
commit 334b67488a
8 changed files with 104 additions and 27 deletions

View File

@ -81,7 +81,7 @@ class UserAdminAPI(APIView):
keyword = request.GET.get("keyword", None) keyword = request.GET.get("keyword", None)
if keyword: if keyword:
user = user.filter(Q(username__contains=keyword) | user = user.filter(Q(username__icontains=keyword) |
Q(real_name__contains=keyword) | Q(userprofile__real_name__icontains=keyword) |
Q(email__contains=keyword)) Q(email__icontains=keyword))
return self.success(self.paginate_data(request, user, UserSerializer)) return self.success(self.paginate_data(request, user, UserSerializer))

View File

@ -11,7 +11,7 @@ from django.conf import settings
from account.models import User from account.models import User
from conf.models import JudgeServer from conf.models import JudgeServer
from contest.models import ContestRuleType, ACMContestRank, OIContestRank, ContestStatus from contest.models import ContestRuleType, ACMContestRank, OIContestRank, ContestStatus
from judge.languages import languages from judge.languages import languages, spj_languages
from options.options import SysOptions from options.options import SysOptions
from problem.models import Problem, ProblemRuleType from problem.models import Problem, ProblemRuleType
from submission.models import JudgeStatus, Submission from submission.models import JudgeStatus, Submission
@ -30,16 +30,9 @@ def process_pending_task():
judge_task.delay(**data) judge_task.delay(**data)
class JudgeDispatcher(object): class DispatcherBase(object):
def __init__(self, submission_id, problem_id): def __init__(self):
self.token = hashlib.sha256(SysOptions.judge_server_token.encode("utf-8")).hexdigest() self.token = hashlib.sha256(SysOptions.judge_server_token.encode("utf-8")).hexdigest()
self.submission = Submission.objects.get(id=submission_id)
self.contest_id = self.submission.contest_id
if self.contest_id:
self.problem = Problem.objects.select_related("contest").get(id=problem_id, contest_id=self.contest_id)
self.contest = self.problem.contest
else:
self.problem = Problem.objects.get(id=problem_id)
def _request(self, url, data=None): def _request(self, url, data=None):
kwargs = {"headers": {"X-Judge-Server-Token": self.token}} kwargs = {"headers": {"X-Judge-Server-Token": self.token}}
@ -69,6 +62,39 @@ class JudgeDispatcher(object):
server.used_instance_number = F("task_number") - 1 server.used_instance_number = F("task_number") - 1
server.save() server.save()
class SPJCompiler(DispatcherBase):
def __init__(self, spj_code, spj_version, spj_language):
super().__init__()
spj_compile_config = list(filter(lambda config: spj_language == config["name"], spj_languages))[0]["spj"][
"compile"]
self.data = {
"src": spj_code,
"spj_version": spj_version,
"spj_compile_config": spj_compile_config
}
def compile_spj(self):
server = self.choose_judge_server()
if not server:
return "No available judge_server"
result = self._request(urljoin(server.service_url, "compile_spj"), data=self.data)
self.release_judge_server(server.id)
if result["err"]:
return result["data"]
class JudgeDispatcher(DispatcherBase):
def __init__(self, submission_id, problem_id):
super().__init__()
self.submission = Submission.objects.get(id=submission_id)
self.contest_id = self.submission.contest_id
if self.contest_id:
self.problem = Problem.objects.select_related("contest").get(id=problem_id, contest_id=self.contest_id)
self.contest = self.problem.contest
else:
self.problem = Problem.objects.get(id=problem_id)
def _compute_statistic_info(self, resp_data): def _compute_statistic_info(self, resp_data):
# 用时和内存占用保存为多个测试点中最长的那个 # 用时和内存占用保存为多个测试点中最长的那个
self.submission.statistic_info["time_cost"] = max([x["cpu_time"] for x in resp_data]) self.submission.statistic_info["time_cost"] = max([x["cpu_time"] for x in resp_data])
@ -90,7 +116,7 @@ class JudgeDispatcher(object):
return return
self.submission.statistic_info["score"] = score self.submission.statistic_info["score"] = score
def judge(self, output=False): def judge(self, output=True):
server = self.choose_judge_server() server = self.choose_judge_server()
if not server: if not server:
data = {"submission_id": self.submission.id, "problem_id": self.problem.id} data = {"submission_id": self.submission.id, "problem_id": self.problem.id}
@ -100,7 +126,7 @@ class JudgeDispatcher(object):
sub_config = list(filter(lambda item: self.submission.language == item["name"], languages))[0] sub_config = list(filter(lambda item: self.submission.language == item["name"], languages))[0]
spj_config = {} spj_config = {}
if self.problem.spj_code: if self.problem.spj_code:
for lang in languages: for lang in spj_languages:
if lang["name"] == self.problem.spj_language: if lang["name"] == self.problem.spj_language:
spj_config = lang["spj"] spj_config = lang["spj"]
break break
@ -153,12 +179,6 @@ class JudgeDispatcher(object):
# 至此判题结束,尝试处理任务队列中剩余的任务 # 至此判题结束,尝试处理任务队列中剩余的任务
process_pending_task() process_pending_task()
def compile_spj(self, service_url, src, spj_version, spj_compile_config, test_case_id):
data = {"src": src, "spj_version": spj_version,
"spj_compile_config": spj_compile_config,
"test_case_id": test_case_id}
return self._request(urljoin(service_url, "compile_spj"), data=data)
def update_problem_status(self): def update_problem_status(self):
result = str(self.submission.result) result = str(self.submission.result)
problem_id = str(self.problem.id) problem_id = str(self.problem.id)
@ -201,10 +221,10 @@ class JudgeDispatcher(object):
user_profile.accepted_number += 1 user_profile.accepted_number += 1
else: else:
if oi_problems_status[problem_id]["status"] == JudgeStatus.ACCEPTED and \ if oi_problems_status[problem_id]["status"] == JudgeStatus.ACCEPTED and \
self.submission.result != JudgeStatus.ACCEPTED: self.submission.result != JudgeStatus.ACCEPTED:
user_profile.accepted_number -= 1 user_profile.accepted_number -= 1
elif oi_problems_status[problem_id]["status"] != JudgeStatus.ACCEPTED and \ elif oi_problems_status[problem_id]["status"] != JudgeStatus.ACCEPTED and \
self.submission.result == JudgeStatus: self.submission.result == JudgeStatus:
user_profile.accepted_number += 1 user_profile.accepted_number += 1
# minus last time score, add this time score # minus last time score, add this time score

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-11-16 12:42
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('problem', '0009_auto_20171011_1214'),
]
operations = [
migrations.AddField(
model_name='problem',
name='spj_compile_ok',
field=models.BooleanField(default=False),
),
]

View File

@ -56,6 +56,7 @@ class Problem(models.Model):
spj_language = models.CharField(max_length=32, blank=True, null=True) spj_language = models.CharField(max_length=32, blank=True, null=True)
spj_code = models.TextField(blank=True, null=True) spj_code = models.TextField(blank=True, null=True)
spj_version = models.CharField(max_length=32, blank=True, null=True) spj_version = models.CharField(max_length=32, blank=True, null=True)
spj_compile_ok = models.BooleanField(default=False)
rule_type = models.CharField(max_length=32) rule_type = models.CharField(max_length=32)
visible = models.BooleanField(default=True) visible = models.BooleanField(default=True)
difficulty = models.CharField(max_length=32) difficulty = models.CharField(max_length=32)

View File

@ -79,6 +79,12 @@ class TagSerializer(serializers.ModelSerializer):
fields = "__all__" fields = "__all__"
class CompileSPJSerializer(serializers.Serializer):
id = serializers.IntegerField()
spj_language = serializers.ChoiceField(choices=spj_language_names)
spj_code = serializers.CharField()
class BaseProblemSerializer(serializers.ModelSerializer): class BaseProblemSerializer(serializers.ModelSerializer):
samples = serializers.JSONField() samples = serializers.JSONField()
test_case_score = serializers.JSONField() test_case_score = serializers.JSONField()
@ -125,3 +131,5 @@ class ContestProblemSafeSerializer(BaseProblemSerializer):
class ContestProblemMakePublicSerializer(serializers.Serializer): class ContestProblemMakePublicSerializer(serializers.Serializer):
id = serializers.IntegerField() id = serializers.IntegerField()
display_id = serializers.CharField(max_length=32) display_id = serializers.CharField(max_length=32)

View File

@ -1,9 +1,11 @@
from django.conf.urls import url from django.conf.urls import url
from ..views.admin import ContestProblemAPI, ProblemAPI, TestCaseAPI, MakeContestProblemPublicAPIView from ..views.admin import ContestProblemAPI, ProblemAPI, TestCaseAPI, MakeContestProblemPublicAPIView
from ..views.admin import CompileSPJAPI
urlpatterns = [ urlpatterns = [
url(r"^test_case/?$", TestCaseAPI.as_view(), name="test_case_api"), url(r"^test_case/?$", TestCaseAPI.as_view(), name="test_case_api"),
url(r"^compile_spj/?$", CompileSPJAPI.as_view(), name="compile_spj"),
url(r"^problem/?$", ProblemAPI.as_view(), name="problem_admin_api"), url(r"^problem/?$", ProblemAPI.as_view(), name="problem_admin_api"),
url(r"^contest/problem/?$", ContestProblemAPI.as_view(), name="contest_problem_admin_api"), url(r"^contest/problem/?$", ContestProblemAPI.as_view(), name="contest_problem_admin_api"),
url(r"^contest_problem/make_public/?$", MakeContestProblemPublicAPIView.as_view(), name="make_public_api"), url(r"^contest_problem/make_public/?$", MakeContestProblemPublicAPIView.as_view(), name="make_public_api"),

View File

@ -8,12 +8,13 @@ from django.conf import settings
from django.http import StreamingHttpResponse from django.http import StreamingHttpResponse
from account.decorators import problem_permission_required from account.decorators import problem_permission_required
from judge.dispatcher import SPJCompiler
from contest.models import Contest from contest.models import Contest
from utils.api import APIView, CSRFExemptAPIView, validate_serializer from utils.api import APIView, CSRFExemptAPIView, validate_serializer
from utils.shortcuts import rand_str, natural_sort_key from utils.shortcuts import rand_str, natural_sort_key
from ..models import Problem, ProblemRuleType, ProblemTag from ..models import Problem, ProblemRuleType, ProblemTag
from ..serializers import (CreateContestProblemSerializer, ContestProblemAdminSerializer, from ..serializers import (CreateContestProblemSerializer, ContestProblemAdminSerializer, CompileSPJSerializer,
CreateProblemSerializer, EditProblemSerializer, EditContestProblemSerializer, CreateProblemSerializer, EditProblemSerializer, EditContestProblemSerializer,
ProblemAdminSerializer, TestCaseUploadForm, ContestProblemMakePublicSerializer) ProblemAdminSerializer, TestCaseUploadForm, ContestProblemMakePublicSerializer)
@ -60,7 +61,7 @@ class TestCaseAPI(CSRFExemptAPIView):
return self.error("Test case does not exists") return self.error("Test case does not exists")
name_list = self.filter_name_list(os.listdir(test_case_dir), problem.spj) name_list = self.filter_name_list(os.listdir(test_case_dir), problem.spj)
name_list.append("info") name_list.append("info")
file_name = os.path.join(test_case_dir, problem.test_case_id) file_name = os.path.join(test_case_dir, problem.test_case_id + ".zip")
with zipfile.ZipFile(file_name, "w") as file: with zipfile.ZipFile(file_name, "w") as file:
for test_case in name_list: for test_case in name_list:
file.write(f"{test_case_dir}/{test_case}", test_case) file.write(f"{test_case_dir}/{test_case}", test_case)
@ -134,6 +135,31 @@ class TestCaseAPI(CSRFExemptAPIView):
return self.success({"id": test_case_id, "info": ret, "hint": hint, "spj": spj}) return self.success({"id": test_case_id, "info": ret, "hint": hint, "spj": spj})
class CompileSPJAPI(APIView):
@validate_serializer(CompileSPJSerializer)
@problem_permission_required
def post(self, request):
data = request.data
try:
problem = Problem.objects.get(pk=data["id"])
except Problem.DoesNotExist:
return self.error("Problem does not exist")
spj_version = rand_str(8)
problem.spj = True
problem.spj_version = spj_version
problem.spj_language = data["spj_language"]
problem.spj_code = data["spj_code"]
error = SPJCompiler(data["spj_code"], spj_version, data["spj_language"]).compile_spj()
if error:
problem.spj_compile_ok = False
problem.save()
return self.error(error)
else:
problem.spj_compile_ok = True
problem.save()
return self.success()
class ProblemBase(APIView): class ProblemBase(APIView):
def common_checks(self, request): def common_checks(self, request):
data = request.data data = request.data

View File

@ -154,7 +154,7 @@ class SubmissionListAPI(APIView):
if (myself and myself == "1") or not SysOptions.submission_list_show_all: if (myself and myself == "1") or not SysOptions.submission_list_show_all:
submissions = submissions.filter(user_id=request.user.id) submissions = submissions.filter(user_id=request.user.id)
elif username: elif username:
submissions = submissions.filter(username=username) submissions = submissions.filter(username__icontains=username)
if result: if result:
submissions = submissions.filter(result=result) submissions = submissions.filter(result=result)
data = self.paginate_data(request, submissions) data = self.paginate_data(request, submissions)
@ -184,7 +184,7 @@ class ContestSubmissionListAPI(APIView):
if myself and myself == "1": if myself and myself == "1":
submissions = submissions.filter(user_id=request.user.id) submissions = submissions.filter(user_id=request.user.id)
elif username: elif username:
submissions = submissions.filter(username=username) submissions = submissions.filter(username__icontains=username)
if result: if result:
submissions = submissions.filter(result=result) submissions = submissions.filter(result=result)