diff --git a/contest/serializers.py b/contest/serializers.py index 528fff4c..3e842fb1 100644 --- a/contest/serializers.py +++ b/contest/serializers.py @@ -27,7 +27,7 @@ class EditConetestSeriaizer(serializers.Serializer): real_time_rank = serializers.BooleanField() -class ContestSerializer(serializers.ModelSerializer): +class ContestAdminSerializer(serializers.ModelSerializer): start_time = DateTimeTZField() end_time = DateTimeTZField() create_time = DateTimeTZField() @@ -36,6 +36,11 @@ class ContestSerializer(serializers.ModelSerializer): status = serializers.CharField() contest_type = serializers.CharField() + class Meta: + model = Contest + + +class ContestSerializer(ContestAdminSerializer): class Meta: model = Contest exclude = ('password', 'visible') diff --git a/contest/tests.py b/contest/tests.py index 93b839fc..7d94afeb 100644 --- a/contest/tests.py +++ b/contest/tests.py @@ -74,6 +74,16 @@ class ContestAPITest(APITestCase): response = self.client.get("{}?id={}".format(self.url, contest_id)) self.assertSuccess(response) + def test_contest_password(self): + contest_id = self.create_contest().data["data"]["id"] + self.create_user("test", "test123") + url = self.reverse("contest_password_api") + resp = self.client.post(url, {"contest_id": contest_id, "password": "error_password"}) + self.assertFailed(resp) + + resp = self.client.post(url, {"contest_id": contest_id, "password": DEFAULT_CONTEST_DATA["password"]}) + self.assertSuccess(resp) + class ContestAnnouncementAPITest(APITestCase): def setUp(self): diff --git a/contest/urls/oj.py b/contest/urls/oj.py index 6c093438..eccb1f5a 100644 --- a/contest/urls/oj.py +++ b/contest/urls/oj.py @@ -1,9 +1,11 @@ from django.conf.urls import url from ..views.oj import ContestAnnouncementListAPI, ContestAPI +from ..views.oj import ContestPasswordVerifyAPI urlpatterns = [ url(r"^contest/?$", ContestAPI.as_view(), name="contest_api"), + url(r"^contest/password/?$", ContestPasswordVerifyAPI.as_view(), name="contest_password_api"), url(r"^contest/announcement/?$", ContestAnnouncementListAPI.as_view(), name="contest_announcement_api"), ] diff --git a/contest/views/admin.py b/contest/views/admin.py index 60bb161e..5f9a62c6 100644 --- a/contest/views/admin.py +++ b/contest/views/admin.py @@ -3,7 +3,7 @@ import dateutil.parser from utils.api import APIView, validate_serializer from ..models import Contest, ContestAnnouncement -from ..serializers import (ContestAnnouncementSerializer, ContestSerializer, +from ..serializers import (ContestAnnouncementSerializer, ContestAdminSerializer, CreateConetestSeriaizer, CreateContestAnnouncementSerializer, EditConetestSeriaizer) @@ -21,7 +21,7 @@ class ContestAPI(APIView): if not data["password"]: data["password"] = None contest = Contest.objects.create(**data) - return self.success(ContestSerializer(contest).data) + return self.success(ContestAdminSerializer(contest).data) @validate_serializer(EditConetestSeriaizer) def put(self, request): @@ -41,7 +41,7 @@ class ContestAPI(APIView): for k, v in data.items(): setattr(contest, k, v) contest.save() - return self.success(ContestSerializer(contest).data) + return self.success(ContestAdminSerializer(contest).data) def get(self, request): contest_id = request.GET.get("id") @@ -50,7 +50,7 @@ class ContestAPI(APIView): contest = Contest.objects.get(id=contest_id) if request.user.is_admin() and contest.created_by != request.user: return self.error("Contest does not exist") - return self.success(ContestSerializer(contest).data) + return self.success(ContestAdminSerializer(contest).data) except Contest.DoesNotExist: return self.error("Contest does not exist") @@ -62,7 +62,7 @@ class ContestAPI(APIView): if request.user.is_admin(): contests = contests.filter(created_by=request.user) - return self.success(self.paginate_data(request, contests, ContestSerializer)) + return self.success(self.paginate_data(request, contests, ContestAdminSerializer)) class ContestAnnouncementAPI(APIView): diff --git a/contest/views/oj.py b/contest/views/oj.py index b576fa52..08daa3e2 100644 --- a/contest/views/oj.py +++ b/contest/views/oj.py @@ -38,7 +38,7 @@ class ContestAPI(APIView): class ContestPasswordVerifyAPI(APIView): @validate_serializer(ContestPasswordVerifySerializer) @login_required - def get(self, request): + def post(self, request): data = request.data try: contest = Contest.objects.get(id=data["contest_id"], visible=True, password__isnull=False) diff --git a/problem/tests.py b/problem/tests.py index caa6ad68..34e0f496 100644 --- a/problem/tests.py +++ b/problem/tests.py @@ -9,6 +9,17 @@ from utils.api.tests import APITestCase from .models import ProblemTag from .views.admin import TestCaseUploadAPI +from contest.tests import DEFAULT_CONTEST_DATA + +DEFAULT_PROBLEM_DATA = {"_id": "A-110", "title": "test", "description": "

test

", "input_description": "test", + "output_description": "test", "time_limit": 1000, "memory_limit": 256, "difficulty": "Low", + "visible": True, "tags": ["test"], "languages": ["C", "C++", "Java", "Python2"], "template": {}, + "samples": [{"input": "test", "output": "test"}], "spj": False, "spj_language": "C", + "spj_code": "", "test_case_id": "499b26290cc7994e0b497212e842ea85", + "test_case_score": [{"output_name": "1.out", "input_name": "1.in", "output_size": 0, + "stripped_output_md5": "d41d8cd98f00b204e9800998ecf8427e", + "input_size": 0, "score": 0}], + "rule_type": "ACM", "hint": "

test

", "source": "test"} class ProblemTagListAPITest(APITestCase): @@ -83,15 +94,7 @@ class ProblemAdminAPITest(APITestCase): def setUp(self): self.url = self.reverse("problem_admin_api") self.create_super_admin() - self.data = {"_id": "A-110", "title": "test", "description": "

test

", "input_description": "test", - "output_description": "test", "time_limit": 1000, "memory_limit": 256, "difficulty": "Low", - "visible": True, "tags": ["test"], "languages": ["C", "C++", "Java", "Python2"], "template": {}, - "samples": [{"input": "test", "output": "test"}], "spj": False, "spj_language": "C", - "spj_code": "", "test_case_id": "499b26290cc7994e0b497212e842ea85", - "test_case_score": [{"output_name": "1.out", "input_name": "1.in", "output_size": 0, - "stripped_output_md5": "d41d8cd98f00b204e9800998ecf8427e", - "input_size": 0, "score": 0}], - "rule_type": "ACM", "hint": "

test

", "source": "test"} + self.data = DEFAULT_PROBLEM_DATA def test_create_problem(self): resp = self.client.post(self.url, data=self.data) @@ -131,3 +134,92 @@ class ProblemAdminAPITest(APITestCase): data["id"] = problem_id resp = self.client.put(self.url, data=data) self.assertSuccess(resp) + + +class ProblemAPITest(APITestCase): + def setUp(self): + self.url = self.reverse("problem_api") + self.create_admin() + + def create_problem(self): + url = self.reverse("problem_admin_api") + return self.client.post(url, data=DEFAULT_PROBLEM_DATA) + + def test_get_problem_list(self): + self.create_problem() + resp = self.client.get(self.url) + self.assertSuccess(resp) + + def get_one_problem(self): + problem_id = self.create_problem().data["data"]["_id"] + resp = self.client.get(self.url + "?id=" + str(problem_id)) + self.assertSuccess(resp) + + +class ContestProblemAdminTest(APITestCase): + def setUp(self): + self.url = self.reverse("contest_problem_admin_api") + self.create_admin() + + def create_contest(self): + url = self.reverse("contest_admin_api") + return self.client.post(url, data=DEFAULT_CONTEST_DATA) + + def test_create_contest_problem(self): + contest = self.create_contest() + data = DEFAULT_PROBLEM_DATA + data["contest_id"] = contest.data["data"]["id"] + resp = self.client.post(self.url, data=data) + self.assertSuccess(resp) + return resp + + def test_get_contest_problem(self): + contest = self.test_create_contest_problem() + contest_id = contest.data["data"]["id"] + resp = self.client.get(self.url + "?contest_id=" + str(contest_id)) + self.assertSuccess(resp) + self.assertEqual(len(resp.data["data"]), 1) + + def test_get_one_contest_problem(self): + contest = self.test_create_contest_problem() + contest_id = contest.data["data"]["id"] + resp = self.client.get(self.url + "?id=" + str(contest_id)) + self.assertSuccess(resp) + + +class ContestProblemTest(APITestCase): + def setUp(self): + self.url = self.reverse("contest_problem_api") + self.create_admin() + + url = self.reverse("contest_admin_api") + self.contest = self.client.post(url, data=DEFAULT_CONTEST_DATA) + self.data = DEFAULT_PROBLEM_DATA + self.data["contest"] = self.contest.data["data"]["id"] + url = self.reverse("contest_problem_admin_api") + self.problem = self.client.post(url, self.data) + + def test_get_contest_problem_list(self): + contest_id = self.contest.data["data"]["id"] + resp = self.client.get(self.url + "?contest_id=" + str(contest_id)) + self.assertSuccess(resp) + self.assertEqual(len(resp.data["data"]), 1) + + def test_get_one_contest_problem(self): + contest_id = self.contest.data["data"]["id"] + problem_id = self.problem.data["data"]["_id"] + resp = self.client.get("{}?contest_id={}&problem_id={}".format(self.url,contest_id, problem_id)) + self.assertSuccess(resp) + + def test_regular_user_get_contest_problem(self): + self.create_user("test", "test123") + contest_id = self.contest.data["data"]["id"] + problem_id = self.problem.data["data"]["_id"] + resp = self.client.get("{}?contest_id={}&problem_id={}".format(self.url,contest_id, problem_id)) + self.assertFailed(resp) + + url = self.reverse("contest_password_api") + self.client.post(url, {"contest_id": contest_id, "password": DEFAULT_CONTEST_DATA["password"]}) + resp = self.client.get("{}?contest_id={}&problem_id={}".format(self.url,contest_id, problem_id)) + self.assertSuccess(resp) + diff --git a/problem/urls/admin.py b/problem/urls/admin.py index d123f35b..ba0feeb2 100644 --- a/problem/urls/admin.py +++ b/problem/urls/admin.py @@ -5,5 +5,5 @@ from ..views.admin import ContestProblemAPI, ProblemAPI, TestCaseUploadAPI urlpatterns = [ url(r"^test_case/upload/?$", TestCaseUploadAPI.as_view(), name="test_case_upload_api"), url(r"^problem/?$", ProblemAPI.as_view(), name="problem_admin_api"), - url(r"^contest/problem/?$", ContestProblemAPI.as_view(), name="contest_problem_api") + url(r"^contest/problem/?$", ContestProblemAPI.as_view(), name="contest_problem_admin_api"), ] diff --git a/problem/urls/oj.py b/problem/urls/oj.py index 74503022..c50cafc6 100644 --- a/problem/urls/oj.py +++ b/problem/urls/oj.py @@ -4,6 +4,6 @@ from ..views.oj import ProblemTagAPI, ProblemAPI, ContestProblemAPI urlpatterns = [ url(r"^problem/tags/?$", ProblemTagAPI.as_view(), name="problem_tag_list_api"), - url(r"^problems/?$", ProblemAPI.as_view(), name="problem_list_api"), - url(r"^contest_problems/?$", ContestProblemAPI.as_view(), name="contest_problem_api"), + url(r"^problem/?$", ProblemAPI.as_view(), name="problem_api"), + url(r"^contest/problem/?$", ContestProblemAPI.as_view(), name="contest_problem_api"), ] diff --git a/problem/views/oj.py b/problem/views/oj.py index 4ad6488c..c273bddf 100644 --- a/problem/views/oj.py +++ b/problem/views/oj.py @@ -48,5 +48,13 @@ class ProblemAPI(APIView): class ContestProblemAPI(APIView): @check_contest_permission def get(self, request): + problem_id = request.GET.get("problem_id") + if problem_id: + try: + problem = ContestProblem.objects.get(_id=problem_id, contest=self.contest, visible=True) + except ContestProblem.DoesNotExist: + return self.error("Problem does not exist.") + return self.success(ContestProblemSerializer(problem).data) + contest_problems = ContestProblem.objects.filter(contest=self.contest, visible=True) return self.success(ContestProblemSerializer(contest_problems, many=True).data)