Commit a7e5bbea by Afzal Wali

Create Exam API

parent e577b8a6
...@@ -21,16 +21,16 @@ class ProctoredExam(TimeStampedModel): ...@@ -21,16 +21,16 @@ class ProctoredExam(TimeStampedModel):
# This will be a integration specific ID - say to SoftwareSecure. # This will be a integration specific ID - say to SoftwareSecure.
external_id = models.TextField(null=True, db_index=True) external_id = models.TextField(null=True, db_index=True)
# This is the display name of the course # This is the display name of the Exam (Midterm etc).
exam_name = models.TextField() exam_name = models.TextField()
# Time limit (in minutes) that a student can finish this exam # Time limit (in minutes) that a student can finish this exam.
time_limit_mins = models.IntegerField() time_limit_mins = models.IntegerField()
# Whether this exam actually is proctored or not # Whether this exam actually is proctored or not.
is_proctored = models.BooleanField() is_proctored = models.BooleanField()
# This will be a integration specific ID - say to SoftwareSecure. # Whether this exam will be active.
is_active = models.BooleanField() is_active = models.BooleanField()
class Meta: class Meta:
...@@ -65,7 +65,7 @@ class ProctoredExamStudentAttempt(TimeStampedModel): ...@@ -65,7 +65,7 @@ class ProctoredExamStudentAttempt(TimeStampedModel):
class QuerySetWithUpdateOverride(models.query.QuerySet): class QuerySetWithUpdateOverride(models.query.QuerySet):
""" """
Custom QuerySet class to send the POST_UPDATE_SIGNAL Custom QuerySet class to make an archive copy
every time the object is updated. every time the object is updated.
""" """
def update(self, **kwargs): def update(self, **kwargs):
...@@ -76,7 +76,7 @@ class QuerySetWithUpdateOverride(models.query.QuerySet): ...@@ -76,7 +76,7 @@ class QuerySetWithUpdateOverride(models.query.QuerySet):
class ProctoredExamStudentAllowanceManager(models.Manager): class ProctoredExamStudentAllowanceManager(models.Manager):
""" """
Custom manager to override with the custom queryset Custom manager to override with the custom queryset
to enable the POST_UPDATE_SIGNAL to enable archiving on Allowance updation.
""" """
def get_query_set(self): def get_query_set(self):
return QuerySetWithUpdateOverride(self.model, using=self._db) return QuerySetWithUpdateOverride(self.model, using=self._db)
...@@ -120,7 +120,7 @@ class ProctoredExamStudentAllowanceHistory(TimeStampedModel): ...@@ -120,7 +120,7 @@ class ProctoredExamStudentAllowanceHistory(TimeStampedModel):
value = models.CharField(max_length=255) value = models.CharField(max_length=255)
# Hook up the custom POST_UPDATE_SIGNAL signal to record updations in the ProctoredExamStudentAllowanceHistory table. # Hook up the post_save signal to record creations in the ProctoredExamStudentAllowanceHistory table.
@receiver(post_save, sender=ProctoredExamStudentAllowance) @receiver(post_save, sender=ProctoredExamStudentAllowance)
def on_allowance_saved(sender, instance, created, **kwargs): # pylint: disable=unused-argument def on_allowance_saved(sender, instance, created, **kwargs): # pylint: disable=unused-argument
""" """
......
...@@ -12,5 +12,10 @@ urlpatterns = patterns( # pylint: disable=invalid-name ...@@ -12,5 +12,10 @@ urlpatterns = patterns( # pylint: disable=invalid-name
views.StudentProctoredExamStatus.as_view(), views.StudentProctoredExamStatus.as_view(),
name='edx_proctoring.proctored_exam.status' name='edx_proctoring.proctored_exam.status'
), ),
url(
r'edx_proctoring/v1/proctored_exam/create$',
views.CreateExamView.as_view(),
name='edx_proctoring.proctored_exam.create'
),
url(r'^', include('rest_framework.urls', namespace='rest_framework')) url(r'^', include('rest_framework.urls', namespace='rest_framework'))
) )
...@@ -3,9 +3,11 @@ Proctored Exams HTTP-based API endpoints ...@@ -3,9 +3,11 @@ Proctored Exams HTTP-based API endpoints
""" """
import logging import logging
from django.db import IntegrityError
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
from .utils import AuthenticatedAPIView from .utils import AuthenticatedAPIView
...@@ -33,3 +35,59 @@ class StudentProctoredExamStatus(AuthenticatedAPIView): ...@@ -33,3 +35,59 @@ class StudentProctoredExamStatus(AuthenticatedAPIView):
} }
return Response(response_dict, status=status.HTTP_200_OK) return Response(response_dict, status=status.HTTP_200_OK)
class CreateExamView(AuthenticatedAPIView):
"""
Creates a new Exam.
POST /edx_proctoring/v1/proctored_exam/create
{
"course_id": "edX/DemoX/Demo_Course",
"content_id": "",
"exam_name": "Midterm",
"time_limit_mins": "90",
"is_proctored": true,
"external_id": "",
"is_active": true,
}
**Post Parameters**
* course_id: The unique identifier for the course.
* content_id: This will be the pointer to the id of the piece of course_ware which is the proctored exam.
* exam_name: This is the display name of the Exam (Midterm etc).
* time_limit_mins: Time limit (in minutes) that a student can finish this exam.
* is_proctored: Whether this exam actually is proctored or not.
* external_id: This will be a integration specific ID - say to SoftwareSecure.
* is_active: Whether this exam will be active.
**Response Values**
* {'exam_id': ##}, The exam_id of the created Proctored Exam.
**Exceptions**
* HTTP_400_BAD_REQUEST, data={"message": "Trying to create a duplicate exam."}
"""
def post(self, request):
"""
Http POST handler.
"""
try:
exam_id = create_exam(
course_id=request.DATA.get('course_id', ""),
content_id=request.DATA.get('content_id', ""),
exam_name=request.DATA.get('exam_name', ""),
time_limit_mins=request.DATA.get('time_limit_mins', ""),
is_proctored=True if request.DATA.get('is_proctored', "False").lower()=='true' else False,
external_id=request.DATA.get('external_id', ""),
is_active=True if request.DATA.get('is_active', "").lower()=='true' else False,
)
return Response({'exam_id': exam_id})
except IntegrityError:
return Response(
status=status.HTTP_400_BAD_REQUEST,
data={"message": u"Trying to create a duplicate exam."}
)
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