Commit 88c655c1 by Afzal Wali

Some Quality fixes

parent 17f93b7d
...@@ -9,8 +9,8 @@ API which is in the views.py file, per edX coding standards ...@@ -9,8 +9,8 @@ API which is in the views.py file, per edX coding standards
import pytz import pytz
from datetime import datetime from datetime import datetime
from edx_proctoring.exceptions import ( from edx_proctoring.exceptions import (
ProctoredExamAlreadyExists, ProctoredExamNotFoundException, StudentExamAttemptAlreadyExistsException ProctoredExamAlreadyExists, ProctoredExamNotFoundException, StudentExamAttemptAlreadyExistsException,
) StudentExamAttemptDoesNotExistsException)
from edx_proctoring.models import ( from edx_proctoring.models import (
ProctoredExam, ProctoredExamStudentAllowance, ProctoredExamStudentAttempt ProctoredExam, ProctoredExamStudentAllowance, ProctoredExamStudentAttempt
) )
...@@ -150,7 +150,7 @@ def stop_exam_attempt(exam_id, user_id): ...@@ -150,7 +150,7 @@ def stop_exam_attempt(exam_id, user_id):
""" """
exam_attempt_obj = ProctoredExamStudentAttempt.get_student_exam_attempt(exam_id, user_id) exam_attempt_obj = ProctoredExamStudentAttempt.get_student_exam_attempt(exam_id, user_id)
if exam_attempt_obj is None: if exam_attempt_obj is None:
raise StudentExamAttemptAlreadyExistsException raise StudentExamAttemptDoesNotExistsException
else: else:
exam_attempt_obj.completed_at = datetime.now(pytz.UTC) exam_attempt_obj.completed_at = datetime.now(pytz.UTC)
exam_attempt_obj.save() exam_attempt_obj.save()
......
...@@ -5,20 +5,23 @@ Specialized exceptions for the Notification subsystem ...@@ -5,20 +5,23 @@ Specialized exceptions for the Notification subsystem
class ProctoredExamAlreadyExists(Exception): class ProctoredExamAlreadyExists(Exception):
""" """
Generic exception when a look up fails. Since we are abstracting away the backends Raised when trying to create an Exam that already exists.
we need to catch any native exceptions and re-throw as a generic exception
""" """
class ProctoredExamNotFoundException(Exception): class ProctoredExamNotFoundException(Exception):
""" """
Generic exception when a look up fails. Since we are abstracting away the backends Raised when a look up fails.
we need to catch any native exceptions and re-throw as a generic exception
""" """
class StudentExamAttemptAlreadyExistsException(Exception): class StudentExamAttemptAlreadyExistsException(Exception):
""" """
Generic exception when a look up fails. Since we are abstracting away the backends Raised when trying to start an exam when an Exam Attempt already exists.
we need to catch any native exceptions and re-throw as a generic exception
""" """
class StudentExamAttemptDoesNotExistsException(Exception):
"""
Raised when trying to stop an exam attempt where the Exam Attempt doesn't exist.
"""
...@@ -4,7 +4,13 @@ from edx_proctoring.models import ProctoredExam ...@@ -4,7 +4,13 @@ from edx_proctoring.models import ProctoredExam
class ProctoredExamSerializer(serializers.ModelSerializer): class ProctoredExamSerializer(serializers.ModelSerializer):
"""
Serializer for the ProctoredExam Model.
"""
class Meta: class Meta:
"""
Meta Class
"""
model = ProctoredExam model = ProctoredExam
fields = ( fields = (
"course_id", "content_id", "external_id", "exam_name", "course_id", "content_id", "external_id", "exam_name",
......
...@@ -3,12 +3,11 @@ All tests for the models.py ...@@ -3,12 +3,11 @@ All tests for the models.py
""" """
from datetime import datetime from datetime import datetime
import pytz import pytz
from edx_proctoring.api import create_exam, update_exam, get_exam_by_id, get_exam_by_content_id, add_allowance_for_user, \ from edx_proctoring.api import create_exam, update_exam, get_exam_by_id, get_exam_by_content_id, \
remove_allowance_for_user, start_exam_attempt, stop_exam_attempt add_allowance_for_user, remove_allowance_for_user, start_exam_attempt, stop_exam_attempt
from edx_proctoring.exceptions import ProctoredExamAlreadyExists, ProctoredExamNotFoundException, \ from edx_proctoring.exceptions import ProctoredExamAlreadyExists, ProctoredExamNotFoundException, \
StudentExamAttemptAlreadyExistsException StudentExamAttemptAlreadyExistsException
from edx_proctoring.models import ProctoredExam, ProctoredExamStudentAllowance, ProctoredExamStudentAllowanceHistory, \ from edx_proctoring.models import ProctoredExam, ProctoredExamStudentAllowance, ProctoredExamStudentAttempt
ProctoredExamStudentAttempt
from .utils import ( from .utils import (
LoggedInTestCase LoggedInTestCase
...@@ -35,6 +34,9 @@ class ProctoredExamApiTests(LoggedInTestCase): ...@@ -35,6 +34,9 @@ class ProctoredExamApiTests(LoggedInTestCase):
self.external_id = 'test_external_id' self.external_id = 'test_external_id'
def _create_proctored_exam(self): def _create_proctored_exam(self):
"""
Calls the api's create_exam to create an exam object.
"""
return create_exam( return create_exam(
course_id=self.course_id, course_id=self.course_id,
content_id=self.content_id, content_id=self.content_id,
...@@ -43,6 +45,10 @@ class ProctoredExamApiTests(LoggedInTestCase): ...@@ -43,6 +45,10 @@ class ProctoredExamApiTests(LoggedInTestCase):
) )
def _create_student_exam_attempt_entry(self): def _create_student_exam_attempt_entry(self):
"""
Creates the ProctoredExamStudentAttempt object.
"""
proctored_exam_id = self._create_proctored_exam() proctored_exam_id = self._create_proctored_exam()
return ProctoredExamStudentAttempt.objects.create( return ProctoredExamStudentAttempt.objects.create(
proctored_exam_id=proctored_exam_id, proctored_exam_id=proctored_exam_id,
......
...@@ -19,7 +19,8 @@ urlpatterns = patterns( # pylint: disable=invalid-name ...@@ -19,7 +19,8 @@ urlpatterns = patterns( # pylint: disable=invalid-name
name='edx_proctoring.proctored_exam.exam' name='edx_proctoring.proctored_exam.exam'
), ),
url( url(
r'edx_proctoring/v1/proctored_exam/exam/course_id/{}/content_id/(?P<content_id>\d+)$'.format(settings.COURSE_ID_PATTERN), r'edx_proctoring/v1/proctored_exam/exam/course_id/{}/content_id/(?P<content_id>\d+)$'.format(
settings.COURSE_ID_PATTERN),
views.ProctoredExamView.as_view(), views.ProctoredExamView.as_view(),
name='edx_proctoring.proctored_exam.exam' name='edx_proctoring.proctored_exam.exam'
), ),
......
...@@ -7,7 +7,8 @@ from rest_framework import status ...@@ -7,7 +7,8 @@ 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, \
stop_exam_attempt, add_allowance_for_user, remove_allowance_for_user, get_active_exams_for_user stop_exam_attempt, add_allowance_for_user, remove_allowance_for_user, get_active_exams_for_user
from edx_proctoring.exceptions import ProctoredExamNotFoundException, ProctoredExamAlreadyExists from edx_proctoring.exceptions import ProctoredExamNotFoundException, ProctoredExamAlreadyExists, \
StudentExamAttemptAlreadyExistsException, StudentExamAttemptDoesNotExistsException
from edx_proctoring.serializers import ProctoredExamSerializer from edx_proctoring.serializers import ProctoredExamSerializer
from .utils import AuthenticatedAPIView from .utils import AuthenticatedAPIView
...@@ -115,13 +116,13 @@ class ProctoredExamView(AuthenticatedAPIView): ...@@ -115,13 +116,13 @@ class ProctoredExamView(AuthenticatedAPIView):
is_active=request.DATA.get('is_active', False), is_active=request.DATA.get('is_active', False),
) )
return Response({'exam_id': exam_id}) return Response({'exam_id': exam_id})
except: except ProctoredExamNotFoundException:
return Response( return Response(
status=status.HTTP_400_BAD_REQUEST, status=status.HTTP_400_BAD_REQUEST,
data={"detail": "The exam_id does not exist."} data={"detail": "The exam_id does not exist."}
) )
def get(self, request, exam_id=None, course_id=None, content_id=None): def get(self, request, exam_id=None, course_id=None, content_id=None): # pylint: disable=unused-argument
""" """
HTTP GET handler. HTTP GET handler.
Scenarios: Scenarios:
...@@ -198,10 +199,10 @@ class StudentProctoredExamAttempt(AuthenticatedAPIView): ...@@ -198,10 +199,10 @@ class StudentProctoredExamAttempt(AuthenticatedAPIView):
) )
return Response({'exam_attempt_id': exam_attempt_id}) return Response({'exam_attempt_id': exam_attempt_id})
except Exception: except StudentExamAttemptAlreadyExistsException:
return Response( return Response(
status=status.HTTP_400_BAD_REQUEST, status=status.HTTP_400_BAD_REQUEST,
data={"detail": "Exam already started."} data={"detail": "Error. Trying to start an exam that has already started."}
) )
def put(self, request): def put(self, request):
...@@ -215,66 +216,57 @@ class StudentProctoredExamAttempt(AuthenticatedAPIView): ...@@ -215,66 +216,57 @@ class StudentProctoredExamAttempt(AuthenticatedAPIView):
) )
return Response({"exam_attempt_id": exam_attempt_id}) return Response({"exam_attempt_id": exam_attempt_id})
except Exception: except StudentExamAttemptDoesNotExistsException:
return Response( return Response(
status=status.HTTP_400_BAD_REQUEST, status=status.HTTP_400_BAD_REQUEST,
data={"detail": "Exam Not in progress."} data={"detail": "Error. Trying to stop an exam that is not in progress."}
) )
class ExamAllowanceView(AuthenticatedAPIView): class ExamAllowanceView(AuthenticatedAPIView):
""" """
Endpoint for the ExamAlloawnce
/edx_proctoring/v1/proctored_exam/allowance
Supports:
HTTP PUT: Creates or Updates the allowance for a user.
HTTP DELETE: Removed an allowance for a user.
""" """
def put(self, request): def put(self, request):
""" """
HTTP GET handler. Adds or updates Allowance HTTP GET handler. Adds or updates Allowance
""" """
try: return Response(add_allowance_for_user(
return Response(add_allowance_for_user( exam_id=request.DATA.get('exam_id', ""),
exam_id=request.DATA.get('exam_id', ""), user_id=request.DATA.get('user_id', ""),
user_id=request.DATA.get('user_id', ""), key=request.DATA.get('key', ""),
key=request.DATA.get('key', ""), value=request.DATA.get('value', "")
value=request.DATA.get('value', "") ))
))
except:
return Response(
status=status.HTTP_400_BAD_REQUEST,
data={"detail": "Could not add Allowance."}
)
def delete(self, request): def delete(self, request):
""" """
HTTP DELETE handler. Removes Allowance. HTTP DELETE handler. Removes Allowance.
""" """
try: return Response(remove_allowance_for_user(
return Response(remove_allowance_for_user( exam_id=request.DATA.get('exam_id', ""),
exam_id=request.DATA.get('exam_id', ""), user_id=request.DATA.get('user_id', ""),
user_id=request.DATA.get('user_id', ""), key=request.DATA.get('key', "")
key=request.DATA.get('key', "") ))
))
except:
return Response(
status=status.HTTP_400_BAD_REQUEST,
data={"detail": "Could not remove Allowance."}
)
class ActiveExamsForUserView(AuthenticatedAPIView): class ActiveExamsForUserView(AuthenticatedAPIView):
""" """
Endpoint for the Active Exams for a user.
/edx_proctoring/v1/proctored_exam/active_exams_for_user
Supports:
HTTP GET: returns a list of active exams for the user
""" """
def get(self, request): def get(self, request):
""" """
returns the get_active_exams_for_user returns the get_active_exams_for_user
""" """
try: return Response(get_active_exams_for_user(
return Response(get_active_exams_for_user( user_id=request.DATA.get('user_id', ""),
user_id=request.DATA.get('user_id', ""), course_id=request.DATA.get('course_id', "")
course_id=request.DATA.get('course_id', "") ))
))
except:
return Response(
status=status.HTTP_400_BAD_REQUEST,
data={"detail": "Error."}
)
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