Commit 6596441a by Muhammad Shoaib

added the require_staff level decorator

parent d1c9b6a2
""" """
All tests for the proctored_exams.py All tests for the proctored_exams.py
""" """
import json
from django.test.client import Client from django.test.client import Client
from django.core.urlresolvers import reverse, NoReverseMatch from django.core.urlresolvers import reverse, NoReverseMatch
from edx_proctoring.models import ProctoredExam from edx_proctoring.models import ProctoredExam
from edx_proctoring.views import require_staff
from .utils import ( from .utils import (
LoggedInTestCase LoggedInTestCase
) )
from mock import Mock
from edx_proctoring.urls import urlpatterns from edx_proctoring.urls import urlpatterns
...@@ -27,9 +30,7 @@ class ProctoredExamsApiTests(LoggedInTestCase): ...@@ -27,9 +30,7 @@ class ProctoredExamsApiTests(LoggedInTestCase):
""" """
Make sure we cannot access any API methods without being logged in Make sure we cannot access any API methods without being logged in
""" """
self.client = Client() # use AnonymousUser on the API calls self.client = Client() # use AnonymousUser on the API calls
for urlpattern in urlpatterns: for urlpattern in urlpatterns:
if hasattr(urlpattern, 'name'): if hasattr(urlpattern, 'name'):
try: try:
...@@ -49,11 +50,16 @@ class StudentProctoredExamAttempt(LoggedInTestCase): ...@@ -49,11 +50,16 @@ class StudentProctoredExamAttempt(LoggedInTestCase):
""" """
Tests for StudentProctoredExamAttempt Tests for StudentProctoredExamAttempt
""" """
def setUp(self):
super(StudentProctoredExamAttempt, self).setUp()
self.user.is_staff = True
self.user.save()
self.client.login_user(self.user)
def test_get_exam_attempt(self): def test_get_exam_attempt(self):
""" """
Test Case for retrieving student proctored exam attempt status. Test Case for retrieving student proctored exam attempt status.
""" """
response = self.client.get( response = self.client.get(
reverse('edx_proctoring.proctored_exam.attempt') reverse('edx_proctoring.proctored_exam.attempt')
) )
...@@ -64,6 +70,12 @@ class ProctoredExamViewTests(LoggedInTestCase): ...@@ -64,6 +70,12 @@ class ProctoredExamViewTests(LoggedInTestCase):
""" """
Tests for the ProctoredExamView Tests for the ProctoredExamView
""" """
def setUp(self):
super(ProctoredExamViewTests, self).setUp()
self.user.is_staff = True
self.user.save()
self.client.login_user(self.user)
def test_create_exam(self): def test_create_exam(self):
""" """
Test the POST method of the exam endpoint to create an exam. Test the POST method of the exam endpoint to create an exam.
...@@ -83,18 +95,20 @@ class ProctoredExamViewTests(LoggedInTestCase): ...@@ -83,18 +95,20 @@ class ProctoredExamViewTests(LoggedInTestCase):
) )
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertGreater(response.data['exam_id'], 0) response_data = json.loads(response.content)
self.assertGreater(response_data['exam_id'], 0)
# Now lookup the exam by giving the exam_id returned and match the data. # Now lookup the exam by giving the exam_id returned and match the data.
response = self.client.get( response = self.client.get(
reverse('edx_proctoring.proctored_exam.exam_by_id', kwargs={'exam_id': response.data['exam_id']}) reverse('edx_proctoring.proctored_exam.exam_by_id', kwargs={'exam_id': response_data['exam_id']})
) )
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(response.data['course_id'], exam_data['course_id']) response_data = json.loads(response.content)
self.assertEqual(response.data['exam_name'], exam_data['exam_name']) self.assertEqual(response_data['course_id'], exam_data['course_id'])
self.assertEqual(response.data['content_id'], exam_data['content_id']) self.assertEqual(response_data['exam_name'], exam_data['exam_name'])
self.assertEqual(response.data['external_id'], exam_data['external_id']) self.assertEqual(response_data['content_id'], exam_data['content_id'])
self.assertEqual(response.data['time_limit_mins'], exam_data['time_limit_mins']) self.assertEqual(response_data['external_id'], exam_data['external_id'])
self.assertEqual(response_data['time_limit_mins'], exam_data['time_limit_mins'])
def test_get_exam_by_id(self): def test_get_exam_by_id(self):
""" """
...@@ -113,8 +127,30 @@ class ProctoredExamViewTests(LoggedInTestCase): ...@@ -113,8 +127,30 @@ class ProctoredExamViewTests(LoggedInTestCase):
reverse('edx_proctoring.proctored_exam.exam_by_id', kwargs={'exam_id': proctored_exam.id}) reverse('edx_proctoring.proctored_exam.exam_by_id', kwargs={'exam_id': proctored_exam.id})
) )
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(response.data['course_id'], proctored_exam.course_id) response_data = json.loads(response.content)
self.assertEqual(response.data['exam_name'], proctored_exam.exam_name) self.assertEqual(response_data['course_id'], proctored_exam.course_id)
self.assertEqual(response.data['content_id'], proctored_exam.content_id) self.assertEqual(response_data['exam_name'], proctored_exam.exam_name)
self.assertEqual(response.data['external_id'], proctored_exam.external_id) self.assertEqual(response_data['content_id'], proctored_exam.content_id)
self.assertEqual(response.data['time_limit_mins'], proctored_exam.time_limit_mins) self.assertEqual(response_data['external_id'], proctored_exam.external_id)
self.assertEqual(response_data['time_limit_mins'], proctored_exam.time_limit_mins)
def test_decorator_staff_user(self):
"""
Test assert require_staff before hitting any api url.
"""
func = Mock()
decorated_func = require_staff(func)
request = self.mock_request()
response = decorated_func(request)
self.assertEqual(response.status_code, 403)
self.assertFalse(func.called)
def mock_request(self):
"""
mock request
"""
request = Mock()
self.user.is_staff = False
self.user.save()
request.user = self.user
return request
...@@ -3,6 +3,7 @@ Proctored Exams HTTP-based API endpoints ...@@ -3,6 +3,7 @@ Proctored Exams HTTP-based API endpoints
""" """
import logging import logging
from django.utils.decorators import method_decorator
from rest_framework import status from rest_framework import status
from rest_framework.response import Response from rest_framework.response import Response
from edx_proctoring.api import create_exam, update_exam, get_exam_by_id, get_exam_by_content_id, start_exam_attempt, \ from edx_proctoring.api import create_exam, update_exam, get_exam_by_id, get_exam_by_content_id, start_exam_attempt, \
...@@ -19,7 +20,7 @@ LOG = logging.getLogger("edx_proctoring_views") ...@@ -19,7 +20,7 @@ LOG = logging.getLogger("edx_proctoring_views")
def require_staff(func): def require_staff(func):
"""View decorator that requires that the user have staff permissions. """ """View decorator that requires that the user have staff permissions. """
def wrapped(request, *args, **kwargs): # pylint: disable=missing-docstring def wrapped(request, *args, **kwargs): # pylint: disable=missing-docstring
if args[0].user.is_staff: if request.user.is_staff:
return func(request, *args, **kwargs) return func(request, *args, **kwargs)
else: else:
return Response( return Response(
...@@ -93,7 +94,7 @@ class ProctoredExamView(AuthenticatedAPIView): ...@@ -93,7 +94,7 @@ class ProctoredExamView(AuthenticatedAPIView):
?course_id=edX/DemoX/Demo_Course&content_id=123 ?course_id=edX/DemoX/Demo_Course&content_id=123
returns an existing exam object matching the course_id and the content_id returns an existing exam object matching the course_id and the content_id
""" """
@require_staff @method_decorator(require_staff)
def post(self, request): def post(self, request):
""" """
Http POST handler. Creates an exam. Http POST handler. Creates an exam.
...@@ -122,7 +123,7 @@ class ProctoredExamView(AuthenticatedAPIView): ...@@ -122,7 +123,7 @@ class ProctoredExamView(AuthenticatedAPIView):
data=serializer.errors data=serializer.errors
) )
@require_staff @method_decorator(require_staff)
def put(self, request): def put(self, request):
""" """
HTTP PUT handler. To update an exam. HTTP PUT handler. To update an exam.
...@@ -209,7 +210,7 @@ class StudentProctoredExamAttempt(AuthenticatedAPIView): ...@@ -209,7 +210,7 @@ class StudentProctoredExamAttempt(AuthenticatedAPIView):
status=status.HTTP_200_OK status=status.HTTP_200_OK
) )
@require_staff @method_decorator(require_staff)
def post(self, request): def post(self, request):
""" """
HTTP POST handler. To start an exam. HTTP POST handler. To start an exam.
...@@ -228,7 +229,7 @@ class StudentProctoredExamAttempt(AuthenticatedAPIView): ...@@ -228,7 +229,7 @@ class StudentProctoredExamAttempt(AuthenticatedAPIView):
data={"detail": "Error. Trying to start an exam that has already started."} data={"detail": "Error. Trying to start an exam that has already started."}
) )
@require_staff @method_decorator(require_staff)
def put(self, request): def put(self, request):
""" """
HTTP POST handler. To stop an exam. HTTP POST handler. To stop an exam.
...@@ -256,7 +257,7 @@ class ExamAllowanceView(AuthenticatedAPIView): ...@@ -256,7 +257,7 @@ class ExamAllowanceView(AuthenticatedAPIView):
HTTP PUT: Creates or Updates the allowance for a user. HTTP PUT: Creates or Updates the allowance for a user.
HTTP DELETE: Removed an allowance for a user. HTTP DELETE: Removed an allowance for a user.
""" """
@require_staff @method_decorator(require_staff)
def put(self, request): def put(self, request):
""" """
HTTP GET handler. Adds or updates Allowance HTTP GET handler. Adds or updates Allowance
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment