diff --git a/oj/local_settings.py b/oj/local_settings.py index 276beb2b..902ca258 100644 --- a/oj/local_settings.py +++ b/oj/local_settings.py @@ -31,9 +31,5 @@ DEBUG = True ALLOWED_HOSTS = ["*"] -# 在 debug 关闭的情况下,静态文件不是有 django runserver 来处理的,应该由 nginx 返回 -# 在 debug 开启的情况下,django 会在下面两个文件夹中寻找对应的静态文件。 -STATICFILES_DIRS = [os.path.join(BASE_DIR, "frontend/static/"), BASE_DIR] +TEST_CASE_DIR = "/tmp" -# 模板文件夹 -OJ_TEMPLATE_DIRS = [os.path.join(BASE_DIR, 'template/src/')] diff --git a/oj/server_settings.py b/oj/server_settings.py index 304ccb9b..e26eefa6 100644 --- a/oj/server_settings.py +++ b/oj/server_settings.py @@ -40,9 +40,6 @@ DEBUG = False ALLOWED_HOSTS = ['*'] -# 在 debug 关闭的情况下,静态文件不是有 django runserver 来处理的,应该由 nginx 返回 -# 在 debug 开启的情况下,django 会在下面两个文件夹中寻找对应的静态文件。 -STATICFILES_DIRS = [os.path.join(BASE_DIR, "static/release/")] -# 模板文件夹 -OJ_TEMPLATE_DIRS = [os.path.join(BASE_DIR, 'template/release/')] +TEST_CASE_DIR = "/test_case" + diff --git a/oj/settings.py b/oj/settings.py index 69fa05f0..d042b3dc 100644 --- a/oj/settings.py +++ b/oj/settings.py @@ -68,7 +68,7 @@ ROOT_URLCONF = 'oj.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': OJ_TEMPLATE_DIRS, + 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ @@ -171,8 +171,6 @@ CELERY_TASK_SERIALIZER = "json" DATABASE_ROUTERS = ['oj.db_router.DBRouter'] -TEST_CASE_DIR = os.path.join(BASE_DIR, 'test_case/') - IMAGE_UPLOAD_DIR = os.path.join(BASE_DIR, 'upload/') # 用于限制用户恶意提交大量代码 diff --git a/oj/urls.py b/oj/urls.py index a591a0b8..ab1353ce 100644 --- a/oj/urls.py +++ b/oj/urls.py @@ -7,4 +7,5 @@ urlpatterns = [ url(r"^api/", include("conf.urls.oj")), url(r"^api/admin/", include("conf.urls.admin")), url(r"^api/", include("problem.urls.oj")), + url(r"^api/admin/", include("problem.urls.admin")), ] diff --git a/problem/serializers.py b/problem/serializers.py index e69de29b..f35a7a03 100644 --- a/problem/serializers.py +++ b/problem/serializers.py @@ -0,0 +1,6 @@ +from django import forms + + +class TestCaseUploadForm(forms.Form): + spj = forms.BooleanField() + file = forms.FileField() diff --git a/problem/tests.py b/problem/tests.py index 5db014c5..8dfdb0e3 100644 --- a/problem/tests.py +++ b/problem/tests.py @@ -1,6 +1,7 @@ from utils.api.tests import APITestCase from .models import ProblemTag +from .views.admin import TestCaseUploadAPI class ProblemTagListAPITest(APITestCase): @@ -10,3 +11,15 @@ class ProblemTagListAPITest(APITestCase): resp = self.client.get(self.reverse("problem_tag_list_api")) self.assertSuccess(resp) self.assertEqual(resp.data["data"], ["name1", "name2"]) + + +class TestCaseUploadAPITest(APITestCase): + def setUp(self): + self.api = TestCaseUploadAPI() + + def test_filter_file_name(self): + self.assertEqual(self.api.filter_name_list(["1.in", "1.out", "2.in", ".DS_Store"], spj=False), ["1.in", "1.out"]) + self.assertEqual(self.api.filter_name_list(["2.in", "2.out"], spj=False), []) + + self.assertEqual(self.api.filter_name_list(["1.in", "1.out", "2.in"], spj=True), ["1.in", "2.in"]) + self.assertEqual(self.api.filter_name_list(["2.in", "3.in"], spj=True), []) diff --git a/problem/urls/admin.py b/problem/urls/admin.py new file mode 100644 index 00000000..941dbedb --- /dev/null +++ b/problem/urls/admin.py @@ -0,0 +1,7 @@ +from django.conf.urls import url + +from ..views.admin import TestCaseUploadAPI + +urlpatterns = [ + url(r"^test_case/upload$", TestCaseUploadAPI.as_view(), name="test_case_upload_api") +] diff --git a/problem/urls/oj.py b/problem/urls/oj.py index c918fbde..d84d0241 100644 --- a/problem/urls/oj.py +++ b/problem/urls/oj.py @@ -1,6 +1,6 @@ from django.conf.urls import url -from ..views import ProblemTagAPI +from ..views.oj import ProblemTagAPI urlpatterns = [ url(r"^tags$", ProblemTagAPI.as_view(), name="problem_tag_list_api") diff --git a/problem/views/__init__.py b/problem/views/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/problem/views/admin.py b/problem/views/admin.py new file mode 100644 index 00000000..c5cd8efc --- /dev/null +++ b/problem/views/admin.py @@ -0,0 +1,68 @@ +import os +import zipfile + +from django.conf import settings + +from utils.api import CSRFExemptAPIView +from account.decorators import admin_required +from utils.shortcuts import rand_str + +from ..serializers import TestCaseUploadForm + + +class TestCaseUploadAPI(CSRFExemptAPIView): + request_parsers = () + + def filter_name_list(self, name_list, spj): + ret = [] + prefix = 1 + if spj: + while True: + in_name = str(prefix) + ".in" + if in_name in name_list: + ret.append(in_name) + prefix += 1 + continue + else: + return sorted(ret) + else: + while True: + in_name = str(prefix) + ".in" + out_name = str(prefix) + ".out" + if in_name in name_list and out_name in name_list: + ret.append(in_name) + ret.append(out_name) + prefix += 1 + continue + else: + return sorted(ret) + + @admin_required + def post(self, request): + form = TestCaseUploadForm(request.POST, request.FILES) + if form.is_valid(): + spj = form.cleaned_data["spj"] + file = form.cleaned_data["file"] + else: + return self.error("Upload failed") + tmp_file = os.path.join("/tmp", rand_str() + ".zip") + with open(tmp_file, "wb") as f: + for chunk in file: + f.write(chunk) + try: + zip_file = zipfile.ZipFile(tmp_file) + except zipfile.BadZipfile: + return self.error("Bad zip file") + name_list = zip_file.namelist() + test_case_list = self.filter_name_list(name_list, spj=spj) + if not test_case_list: + return self.error("Empty file") + + test_case_id = rand_str() + test_case_dir = os.path.join(settings.TEST_CASE_DIR, test_case_id) + os.mkdir(test_case_dir) + + for item in test_case_list: + with open(os.path.join(test_case_dir, item), "wb") as f: + f.write(zip_file.read(item).replace(b"\r\n", b"\n")) + return self.success(test_case_list) diff --git a/problem/views.py b/problem/views/oj.py similarity index 85% rename from problem/views.py rename to problem/views/oj.py index 355df7d9..94496cee 100644 --- a/problem/views.py +++ b/problem/views/oj.py @@ -1,6 +1,6 @@ from utils.api import APIView -from .models import ProblemTag +from ..models import ProblemTag class ProblemTagAPI(APIView): diff --git a/utils/api/_serializers.py b/utils/api/_serializers.py index 798937d4..00a3b8cc 100644 --- a/utils/api/_serializers.py +++ b/utils/api/_serializers.py @@ -11,7 +11,7 @@ class JSONField(serializers.Field): class DateTimeTZField(serializers.DateTimeField): def to_representation(self, value): - self.format = "%Y-%-m-%d %H:%M:%S" + self.format = "%Y-%-m-%d %H:%M:%S %Z" value = timezone.localtime(value) return super(DateTimeTZField, self).to_representation(value) diff --git a/utils/api/api.py b/utils/api/api.py index 231e13f3..280ac68b 100644 --- a/utils/api/api.py +++ b/utils/api/api.py @@ -7,7 +7,7 @@ from django.utils.decorators import method_decorator from django.views.decorators.csrf import csrf_exempt from django.views.generic import View -logger = logging.getLogger(__name__) +logger = logging.getLogger("") class ContentType(object):