diff --git a/problem/decorator.py b/problem/decorator.py new file mode 100644 index 0000000..6eda056 --- /dev/null +++ b/problem/decorator.py @@ -0,0 +1,21 @@ +from rest_framework.response import Response +from rest_framework import status +from django.shortcuts import get_object_or_404 +from problem.models import Problem + + +def view_hidden_problem_permission_required(): + def decorator(func): + def _wrapped_view(request, pid, *args, **kwargs): + problem = get_object_or_404(Problem, pid=pid) + + if not problem.enabled and not request.user.has_perm("problem.view_hidden"): + return Response( + {"detail": "Problem is hidden."}, status=status.HTTP_403_FORBIDDEN + ) + + return func(request, pid=pid, *args, **kwargs) + + return _wrapped_view + + return decorator diff --git a/problem/serializers.py b/problem/serializers.py index c2db657..d62a0f5 100644 --- a/problem/serializers.py +++ b/problem/serializers.py @@ -6,22 +6,38 @@ from segmentoj import tools class ProblemSerializer(serializers.ModelSerializer): + class Meta: model = Problem fields = [ - "pid", - "date_added", - "title", + "pid", + "date_added", + "title", "description", - "allow_html", - "tags", - "enabled", - "memory_limit", + "allow_html", + "tags", + "enabled", + "memory_limit", "time_limit", ] depth = 0 read_only_fields = ["id", "date_added"] + extra_kwargs = { + "description": {"write_only": True}, + } + +class ProblemDescriptionSerializer(serializers.ModelSerializer): + + class Meta: + model = Problem + fields = [ + "pid", + "description", + ] + + depth = 0 + read_only_fields = ["id"] class TagSerializer(serializers.ModelSerializer): diff --git a/problem/tests.py b/problem/tests.py index f4f98cf..574b523 100644 --- a/problem/tests.py +++ b/problem/tests.py @@ -4,7 +4,7 @@ from rest_framework.test import APIRequestFactory, force_authenticate from .models import Problem -from .views import ProblemView, TagView, TagListView +from .views import ProblemView, ProblemDescriptionView, TagView, TagListView from account.models import User # Create your tests here. @@ -21,7 +21,6 @@ def setUp(self): def testZ_get_problem(self): ac_data = { "title": "Simple Problem", - "description": "This is description", "pid": 5, "allow_html": False, "enabled": True, @@ -38,7 +37,6 @@ def testZ_get_problem(self): self.assertIsNotNone(data) self.assertEqual(data.get("title"), ac_data["title"]) - self.assertEqual(data.get("description"), ac_data["description"]) self.assertEqual(data.get("pid"), ac_data["pid"]) self.assertEqual(data.get("allow_html"), ac_data["allow_html"]) self.assertEqual(data.get("enabled"), ac_data["enabled"]) @@ -87,6 +85,28 @@ def testW_change_problem(self): self.assertEqual(target.enabled, ac_data["enabled"]) +class ProblemDescriptionViewTest(TestCase): + fixtures = ["testdatabase.yaml"] + + def setUp(self): + self.base_url = "/api/problem/{pid}/description" + self.factory = APIRequestFactory() + self.view = ProblemDescriptionView.as_view() + + def testZ_get_problem_description(self): + ac_data = { + "description": "This is description" + } + + request = self.factory.get(self.base_url.format(pid=5)) + response = self.view(request, pid=5) + self.assertEqual(response.status_code, status.HTTP_200_OK) + + data = response.data.get("res") + self.assertIsNotNone(data) + self.assertEqual(data.get("description"), ac_data["description"]) + + class TagViewTest(TestCase): fixtures = ["testdatabase.yaml"] diff --git a/problem/views.py b/problem/views.py index 1e43008..0986e0c 100644 --- a/problem/views.py +++ b/problem/views.py @@ -10,22 +10,26 @@ from segmentoj import tools from problem.models import Problem, Tag -from .serializers import ProblemSerializer, ProblemListSerializer, TagSerializer -from segmentoj.decorator import syllable_required, parameter_required +from .serializers import ( + ProblemSerializer, + ProblemDescriptionSerializer, + ProblemListSerializer, + TagSerializer, +) +from segmentoj.decorator import ( + parameter_required, +) from status.models import Status +from .decorator import view_hidden_problem_permission_required class ProblemView(APIView): @method_decorator(parameter_required("pid")) + @method_decorator(view_hidden_problem_permission_required()) def get(self, request, pid): # Get the content of a problem problem = get_object_or_404(Problem, pid=pid) - if not problem.enabled and not request.user.has_perm("problem.view_hidden"): - return Response( - {"detail": "Problem is hidden."}, status=status.HTTP_403_FORBIDDEN - ) - ps = ProblemSerializer(problem) return Response({"res": ps.data}, status=status.HTTP_200_OK) @@ -60,6 +64,16 @@ def delete(self, request, pid): return Response(status=status.HTTP_204_NO_CONTENT) +class ProblemDescriptionView(APIView): + @method_decorator(parameter_required("pid")) + @method_decorator(view_hidden_problem_permission_required()) + def get(self, request, pid): + problem = get_object_or_404(Problem, pid=pid) + + pds = ProblemDescriptionSerializer(problem) + return Response({"res": pds.data}, status=status.HTTP_200_OK) + + class TagView(APIView): @method_decorator(parameter_required("tid")) def get(self, request, tid): @@ -126,7 +140,6 @@ def process_data(x): status=status.HTTP_200_OK, ) - class ProblemListCountView(APIView): def get(self, request): diff --git a/segmentoj/urls.py b/segmentoj/urls.py index 43b4361..48d3c90 100644 --- a/segmentoj/urls.py +++ b/segmentoj/urls.py @@ -52,6 +52,7 @@ # Problem path("api/problem", problem.views.ProblemView.as_view()), path("api/problem/", problem.views.ProblemView.as_view()), + path("api/problem//description", problem.views.ProblemDescriptionView.as_view()), path("api/problem/tag", problem.views.TagView.as_view()), path("api/problem/tag/", problem.views.TagView.as_view()), path("api/problem/list", problem.views.ProblemListView.as_view()),