支持选取已有题目作为比赛题目

This commit is contained in:
zema1 2017-12-03 18:52:32 +08:00
parent 4c2db34b9d
commit 0f9f34df65
7 changed files with 75 additions and 8 deletions

View File

@ -73,7 +73,7 @@ def check_contest_permission(check_type="details"):
else: else:
contest_id = request.GET.get("contest_id") contest_id = request.GET.get("contest_id")
if not contest_id: if not contest_id:
return self.error("Parameter contest_id doesn't exist.") return self.error("Parameter error, contest_id is required")
try: try:
# use self.contest to avoid query contest again in view. # use self.contest to avoid query contest again in view.

View File

@ -10,7 +10,7 @@ from ..models import Contest, ContestAnnouncement, ACMContestRank
from ..serializers import (ContestAnnouncementSerializer, ContestAdminSerializer, from ..serializers import (ContestAnnouncementSerializer, ContestAdminSerializer,
CreateConetestSeriaizer, CreateContestAnnouncementSerializer, CreateConetestSeriaizer, CreateContestAnnouncementSerializer,
EditConetestSeriaizer, EditContestAnnouncementSerializer, EditConetestSeriaizer, EditContestAnnouncementSerializer,
ACMContesHelperSerializer) ACMContesHelperSerializer, )
class ContestAPI(APIView): class ContestAPI(APIView):

View File

@ -4,6 +4,7 @@ from utils.models import JSONField
from account.models import User from account.models import User
from contest.models import Contest from contest.models import Contest
from utils.models import RichTextField from utils.models import RichTextField
from utils.constants import Choices
class ProblemTag(models.Model): class ProblemTag(models.Model):
@ -13,7 +14,7 @@ class ProblemTag(models.Model):
db_table = "problem_tag" db_table = "problem_tag"
class ProblemRuleType(object): class ProblemRuleType(Choices):
ACM = "ACM" ACM = "ACM"
OI = "OI" OI = "OI"

View File

@ -174,3 +174,9 @@ class ExportProblemSerializer(serializers.ModelSerializer):
"input_description", "output_description", "input_description", "output_description",
"test_case_score", "hint", "time_limit", "memory_limit", "samples", "test_case_score", "hint", "time_limit", "memory_limit", "samples",
"template", "spj", "rule_type", "source", "template") "template", "spj", "rule_type", "source", "template")
class AddContestProblemSerializer(serializers.Serializer):
contest_id = serializers.IntegerField()
problem_id = serializers.IntegerField()
display_id = serializers.CharField()

View File

@ -17,7 +17,6 @@ from contest.tests import DEFAULT_CONTEST_DATA
from .views.admin import TestCaseAPI from .views.admin import TestCaseAPI
from .utils import parse_problem_template from .utils import parse_problem_template
DEFAULT_PROBLEM_DATA = {"_id": "A-110", "title": "test", "description": "<p>test</p>", "input_description": "test", DEFAULT_PROBLEM_DATA = {"_id": "A-110", "title": "test", "description": "<p>test</p>", "input_description": "test",
"output_description": "test", "time_limit": 1000, "memory_limit": 256, "difficulty": "Low", "output_description": "test", "time_limit": 1000, "memory_limit": 256, "difficulty": "Low",
"visible": True, "tags": ["test"], "languages": ["C", "C++", "Java", "Python2"], "template": {}, "visible": True, "tags": ["test"], "languages": ["C", "C++", "Java", "Python2"], "template": {},
@ -259,6 +258,29 @@ class ContestProblemTest(ProblemCreateTestBase):
self.assertSuccess(resp) self.assertSuccess(resp)
class AddProblemFromPublicProblemAPITest(ProblemCreateTestBase):
def setUp(self):
admin = self.create_admin()
url = self.reverse("contest_admin_api")
contest_data = copy.deepcopy(DEFAULT_CONTEST_DATA)
contest_data["password"] = ""
contest_data["start_time"] = contest_data["start_time"] + timedelta(hours=1)
self.contest = self.client.post(url, data=contest_data).data["data"]
self.problem = self.add_problem(DEFAULT_PROBLEM_DATA, admin)
self.url = self.reverse("add_contest_problem_from_public_api")
self.data = {
"display_id": "1000",
"contest_id": self.contest["id"],
"problem_id": self.problem.id
}
def test_add_contest_problem(self):
resp = self.client.post(self.url, data=self.data)
self.assertSuccess(resp)
self.assertTrue(Problem.objects.all().exists())
self.assertTrue(Problem.objects.filter(contest_id=self.contest["id"]).exists())
class ParseProblemTemplateTest(APITestCase): class ParseProblemTemplateTest(APITestCase):
def test_parse(self): def test_parse(self):
template_str = """ template_str = """

View File

@ -1,7 +1,7 @@
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 from ..views.admin import CompileSPJAPI, AddContestProblemAPI
urlpatterns = [ urlpatterns = [
url(r"^test_case/?$", TestCaseAPI.as_view(), name="test_case_api"), url(r"^test_case/?$", TestCaseAPI.as_view(), name="test_case_api"),
@ -9,4 +9,5 @@ urlpatterns = [
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"),
url(r"^contest/add_problem_from_public/?$", AddContestProblemAPI.as_view(), name="add_contest_problem_from_public_api"),
] ]

View File

@ -10,7 +10,7 @@ from django.http import StreamingHttpResponse, HttpResponse
from account.decorators import problem_permission_required from account.decorators import problem_permission_required
from judge.dispatcher import SPJCompiler from judge.dispatcher import SPJCompiler
from contest.models import Contest from contest.models import Contest, ContestStatus
from submission.models import Submission from submission.models import Submission
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
@ -18,7 +18,8 @@ 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, CompileSPJSerializer, from ..serializers import (CreateContestProblemSerializer, CompileSPJSerializer,
CreateProblemSerializer, EditProblemSerializer, EditContestProblemSerializer, CreateProblemSerializer, EditProblemSerializer, EditContestProblemSerializer,
ProblemAdminSerializer, TestCaseUploadForm, ContestProblemMakePublicSerializer) ProblemAdminSerializer, TestCaseUploadForm, ContestProblemMakePublicSerializer,
AddContestProblemSerializer)
class TestCaseAPI(CSRFExemptAPIView): class TestCaseAPI(CSRFExemptAPIView):
@ -71,7 +72,8 @@ class TestCaseAPI(CSRFExemptAPIView):
response = HttpResponse() response = HttpResponse()
response["X-Accel-Redirect"] = file_name response["X-Accel-Redirect"] = file_name
else: else:
response = StreamingHttpResponse(FileWrapper(open(file_name, "rb")), content_type="application/octet-stream") response = StreamingHttpResponse(FileWrapper(open(file_name, "rb")),
content_type="application/octet-stream")
response["Content-Disposition"] = f"attachment; filename=problem_{problem.id}_test_cases.zip" response["Content-Disposition"] = f"attachment; filename=problem_{problem.id}_test_cases.zip"
response["Content-Length"] = os.path.getsize(file_name) response["Content-Length"] = os.path.getsize(file_name)
@ -229,6 +231,7 @@ class ProblemAPI(ProblemBase):
@problem_permission_required @problem_permission_required
def get(self, request): def get(self, request):
problem_id = request.GET.get("id") problem_id = request.GET.get("id")
rule_type = request.GET.get("rule_type")
user = request.user user = request.user
if problem_id: if problem_id:
try: try:
@ -240,6 +243,12 @@ class ProblemAPI(ProblemBase):
return self.error("Problem does not exist") return self.error("Problem does not exist")
problems = Problem.objects.filter(contest_id__isnull=True).order_by("-create_time") problems = Problem.objects.filter(contest_id__isnull=True).order_by("-create_time")
if rule_type:
if rule_type not in ProblemRuleType.choices():
return self.error("Invalid rule_type")
else:
problems = problems.filter(rule_type=rule_type)
if not user.can_mgmt_all_problem(): if not user.can_mgmt_all_problem():
problems = problems.filter(created_by=user) problems = problems.filter(created_by=user)
keyword = request.GET.get("keyword") keyword = request.GET.get("keyword")
@ -433,3 +442,31 @@ class MakeContestProblemPublicAPIView(APIView):
problem.save() problem.save()
problem.tags.set(tags) problem.tags.set(tags)
return self.success() return self.success()
class AddContestProblemAPI(APIView):
@validate_serializer(AddContestProblemSerializer)
def post(self, request):
data = request.data
try:
contest = Contest.objects.get(id=data["contest_id"])
problem = Problem.objects.get(id=data["problem_id"])
except (Contest.DoesNotExist, Problem.DoesNotExist):
return self.error("Contest or Problem does not exist")
if contest.status == ContestStatus.CONTEST_ENDED:
return self.error("Contest has ended")
if Problem.objects.filter(contest=contest, _id=data["display_id"]).exists():
return self.error("Duplicate display id in this contest")
tags = problem.tags.all()
problem.pk = None
problem.contest = contest
problem.is_public = True
problem.visible = True
problem._id = request.data["display_id"]
problem.submission_number = problem.accepted_number = 0
problem.statistic_info = {}
problem.save()
problem.tags.set(tags)
return self.success()