diff --git a/account/views/admin.py b/account/views/admin.py index 9d1359f5..7b9259e6 100644 --- a/account/views/admin.py +++ b/account/views/admin.py @@ -81,7 +81,7 @@ class UserAdminAPI(APIView): keyword = request.GET.get("keyword", None) if keyword: - user = user.filter(Q(username__contains=keyword) | - Q(real_name__contains=keyword) | - Q(email__contains=keyword)) + user = user.filter(Q(username__icontains=keyword) | + Q(userprofile__real_name__icontains=keyword) | + Q(email__icontains=keyword)) return self.success(self.paginate_data(request, user, UserSerializer)) diff --git a/judge/dispatcher.py b/judge/dispatcher.py index 4011e4cb..f108f1fb 100644 --- a/judge/dispatcher.py +++ b/judge/dispatcher.py @@ -11,7 +11,7 @@ from django.conf import settings from account.models import User from conf.models import JudgeServer 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 problem.models import Problem, ProblemRuleType from submission.models import JudgeStatus, Submission @@ -30,16 +30,9 @@ def process_pending_task(): judge_task.delay(**data) -class JudgeDispatcher(object): - def __init__(self, submission_id, problem_id): +class DispatcherBase(object): + def __init__(self): 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): kwargs = {"headers": {"X-Judge-Server-Token": self.token}} @@ -69,6 +62,39 @@ class JudgeDispatcher(object): server.used_instance_number = F("task_number") - 1 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): # 用时和内存占用保存为多个测试点中最长的那个 self.submission.statistic_info["time_cost"] = max([x["cpu_time"] for x in resp_data]) @@ -90,7 +116,7 @@ class JudgeDispatcher(object): return self.submission.statistic_info["score"] = score - def judge(self, output=False): + def judge(self, output=True): server = self.choose_judge_server() if not server: 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] spj_config = {} if self.problem.spj_code: - for lang in languages: + for lang in spj_languages: if lang["name"] == self.problem.spj_language: spj_config = lang["spj"] break @@ -153,12 +179,6 @@ class JudgeDispatcher(object): # 至此判题结束,尝试处理任务队列中剩余的任务 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): result = str(self.submission.result) problem_id = str(self.problem.id) @@ -201,10 +221,10 @@ class JudgeDispatcher(object): user_profile.accepted_number += 1 else: 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 elif oi_problems_status[problem_id]["status"] != JudgeStatus.ACCEPTED and \ - self.submission.result == JudgeStatus: + self.submission.result == JudgeStatus: user_profile.accepted_number += 1 # minus last time score, add this time score diff --git a/problem/migrations/0010_problem_spj_compile_ok.py b/problem/migrations/0010_problem_spj_compile_ok.py new file mode 100644 index 00000000..0df1b36b --- /dev/null +++ b/problem/migrations/0010_problem_spj_compile_ok.py @@ -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), + ), + ] diff --git a/problem/models.py b/problem/models.py index 6fb1c799..5116f4b6 100644 --- a/problem/models.py +++ b/problem/models.py @@ -56,6 +56,7 @@ class Problem(models.Model): spj_language = models.CharField(max_length=32, blank=True, null=True) spj_code = models.TextField(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) visible = models.BooleanField(default=True) difficulty = models.CharField(max_length=32) diff --git a/problem/serializers.py b/problem/serializers.py index 529d3f5b..d035e755 100644 --- a/problem/serializers.py +++ b/problem/serializers.py @@ -79,6 +79,12 @@ class TagSerializer(serializers.ModelSerializer): 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): samples = serializers.JSONField() test_case_score = serializers.JSONField() @@ -125,3 +131,5 @@ class ContestProblemSafeSerializer(BaseProblemSerializer): class ContestProblemMakePublicSerializer(serializers.Serializer): id = serializers.IntegerField() display_id = serializers.CharField(max_length=32) + + diff --git a/problem/urls/admin.py b/problem/urls/admin.py index 5dbc4446..d4f99746 100644 --- a/problem/urls/admin.py +++ b/problem/urls/admin.py @@ -1,9 +1,11 @@ from django.conf.urls import url from ..views.admin import ContestProblemAPI, ProblemAPI, TestCaseAPI, MakeContestProblemPublicAPIView +from ..views.admin import CompileSPJAPI urlpatterns = [ 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"^contest/problem/?$", ContestProblemAPI.as_view(), name="contest_problem_admin_api"), url(r"^contest_problem/make_public/?$", MakeContestProblemPublicAPIView.as_view(), name="make_public_api"), diff --git a/problem/views/admin.py b/problem/views/admin.py index d9ae3f2e..6fc54513 100644 --- a/problem/views/admin.py +++ b/problem/views/admin.py @@ -8,12 +8,13 @@ from django.conf import settings from django.http import StreamingHttpResponse from account.decorators import problem_permission_required +from judge.dispatcher import SPJCompiler from contest.models import Contest from utils.api import APIView, CSRFExemptAPIView, validate_serializer from utils.shortcuts import rand_str, natural_sort_key from ..models import Problem, ProblemRuleType, ProblemTag -from ..serializers import (CreateContestProblemSerializer, ContestProblemAdminSerializer, +from ..serializers import (CreateContestProblemSerializer, ContestProblemAdminSerializer, CompileSPJSerializer, CreateProblemSerializer, EditProblemSerializer, EditContestProblemSerializer, ProblemAdminSerializer, TestCaseUploadForm, ContestProblemMakePublicSerializer) @@ -60,7 +61,7 @@ class TestCaseAPI(CSRFExemptAPIView): return self.error("Test case does not exists") name_list = self.filter_name_list(os.listdir(test_case_dir), problem.spj) 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: for test_case in name_list: 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}) +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): def common_checks(self, request): data = request.data diff --git a/submission/views/oj.py b/submission/views/oj.py index a0deb0a7..a3371ffe 100644 --- a/submission/views/oj.py +++ b/submission/views/oj.py @@ -154,7 +154,7 @@ class SubmissionListAPI(APIView): if (myself and myself == "1") or not SysOptions.submission_list_show_all: submissions = submissions.filter(user_id=request.user.id) elif username: - submissions = submissions.filter(username=username) + submissions = submissions.filter(username__icontains=username) if result: submissions = submissions.filter(result=result) data = self.paginate_data(request, submissions) @@ -184,7 +184,7 @@ class ContestSubmissionListAPI(APIView): if myself and myself == "1": submissions = submissions.filter(user_id=request.user.id) elif username: - submissions = submissions.filter(username=username) + submissions = submissions.filter(username__icontains=username) if result: submissions = submissions.filter(result=result)