增加测试数据下载的功能

This commit is contained in:
spxcds 2016-04-06 16:18:31 +08:00
parent 416c2b1b32
commit ff00d880a0
3 changed files with 62 additions and 3 deletions

1
.gitignore vendored
View File

@ -66,3 +66,4 @@ release/
upload/ upload/
custom_settings.py custom_settings.py
docker-compose.yml docker-compose.yml
*.zip

View File

@ -20,7 +20,7 @@ from group.views import (GroupAdminAPIView, GroupMemberAdminAPIView,
from admin.views import AdminTemplateView from admin.views import AdminTemplateView
from problem.views import TestCaseUploadAPIView, ProblemTagAdminAPIView, ProblemAdminAPIView, OpenAPIProblemAPI from problem.views import TestCaseUploadAPIView, TestCaseDownloadAPIView, ProblemTagAdminAPIView, ProblemAdminAPIView, OpenAPIProblemAPI
from submission.views import (SubmissionAPIView, SubmissionAdminAPIView, ContestSubmissionAPIView, from submission.views import (SubmissionAPIView, SubmissionAdminAPIView, ContestSubmissionAPIView,
SubmissionShareAPIView, SubmissionRejudgeAdminAPIView, OpenAPISubmitCodeAPI) SubmissionShareAPIView, SubmissionRejudgeAdminAPIView, OpenAPISubmitCodeAPI)
from judge_dispatcher.views import AdminJudgeServerAPIView from judge_dispatcher.views import AdminJudgeServerAPIView
@ -68,6 +68,7 @@ urlpatterns = [
url(r'^api/admin/contest_problem/public/', MakeContestProblemPublicAPIView.as_view(), url(r'^api/admin/contest_problem/public/', MakeContestProblemPublicAPIView.as_view(),
name="make_contest_problem_public"), 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/test_case_download/$', TestCaseDownloadAPIView.as_view(), name="test_case_download_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"),

View File

@ -6,6 +6,7 @@ import hashlib
import json import json
import logging import logging
from django.http import StreamingHttpResponse
from django.shortcuts import render from django.shortcuts import render
from django.db.models import Q, Count from django.db.models import Q, Count
from django.core.paginator import Paginator from django.core.paginator import Paginator
@ -14,7 +15,8 @@ from django.conf import settings
from rest_framework.views import APIView from rest_framework.views import APIView
from account.models import SUPER_ADMIN, User from account.models import SUPER_ADMIN, User
from account.decorators import super_admin_required from account.decorators import super_admin_required, admin_required
from contest.models import ContestProblem
from utils.shortcuts import (serializer_invalid_response, error_response, from utils.shortcuts import (serializer_invalid_response, error_response,
success_response, paginate, rand_str, error_page) success_response, paginate, rand_str, error_page)
from .serizalizers import (CreateProblemSerializer, EditProblemSerializer, ProblemSerializer, from .serizalizers import (CreateProblemSerializer, EditProblemSerializer, ProblemSerializer,
@ -282,6 +284,61 @@ class TestCaseUploadAPIView(APIView):
return success_response({"file_list": config["test_cases"]}) return success_response({"file_list": config["test_cases"]})
class TestCaseDownloadAPIView(APIView):
"""
下载题目的测试数据
"""
def _is_legal_test_case_file_name(self, file_name):
regex = r"^[1-9]\d*\.(in|out)$"
return re.compile(regex).match(file_name) is not None
def file_iterator(self, big_file, chunk_size=512):
with open(big_file) as f:
while True:
c = f.read(chunk_size)
if c:
yield c
else:
break
@admin_required
def get(self, request):
test_case_id = request.GET.get("test_case_id", None)
if not test_case_id:
return error_response(u"参数错误")
# 防止URL./../../.上层目录遍历
if not re.compile(r"^[1-9a-zA-Z]+$").match(test_case_id):
return error_response(u"参数错误")
try:
# 超级管理员可以下载全部的题目的测试数据
# 普通管理员只能下载自己创建的题目的测试数据
if request.user.admin_type != SUPER_ADMIN:
ContestProblem.objects.get(test_case_id=test_case_id, created_by=request.user)
test_case_dir = os.path.join(settings.TEST_CASE_DIR, test_case_id)
if not os.path.exists(test_case_dir):
return error_response(u"测试用例不存在")
# 压缩测试用例,命名规则为 "test_case" + test_case_id + ".zip"
test_case_zip = os.path.join("/tmp", "test_case-" + test_case_id + ".zip")
zf = zipfile.ZipFile(test_case_zip, "w", zipfile.ZIP_DEFLATED)
for filename in os.listdir(test_case_dir):
if self._is_legal_test_case_file_name(filename):
zf.write(os.path.join(test_case_dir, filename), filename)
zf.close()
# 大文件传输
response = StreamingHttpResponse(self.file_iterator(test_case_zip))
response['Content-Type'] = 'application/octet-stream'
response['Content-Disposition'] = 'attachment;filename=test_case-%s.zip' % test_case_id
return response
except ContestProblem.DoesNotExist:
return error_response(u"题目不存在")
def problem_list_page(request, page=1): def problem_list_page(request, page=1):
""" """
前台的问题列表 前台的问题列表