summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorprathamesh2018-12-19 13:46:40 +0530
committerprathamesh2018-12-19 13:46:40 +0530
commit0e3353d489fd54a2c84c712ae04e44a9f8d8cd90 (patch)
treec481d2eff3512da0c9c72bb33203d4f9f3b3e636
parenta9e36d0ba393bc709c8bd61b133170e9506aa510 (diff)
downloadonline_test-0e3353d489fd54a2c84c712ae04e44a9f8d8cd90.tar.gz
online_test-0e3353d489fd54a2c84c712ae04e44a9f8d8cd90.tar.bz2
online_test-0e3353d489fd54a2c84c712ae04e44a9f8d8cd90.zip
Provide API version 1 for Yaksh
- Serializers for Question, Quiz, QuestionPaper, AnswerPaper - Can create questions, quizzes, question and answer papers - Can check mcq, mcc and code questions - Tests for the API
-rw-r--r--.travis.yml1
-rw-r--r--api/__init__.py0
-rw-r--r--api/apps.py5
-rw-r--r--api/serializers.py25
-rw-r--r--api/tests.py888
-rw-r--r--api/urls.py23
-rw-r--r--api/views.py330
-rw-r--r--online_test/settings.py15
-rw-r--r--online_test/urls.py2
-rw-r--r--yaksh/models.py1
10 files changed, 1290 insertions, 0 deletions
diff --git a/.travis.yml b/.travis.yml
index 59eaa66..e1e7dc8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -22,6 +22,7 @@ script:
- coverage erase
- coverage run -p manage.py test -v 2 --settings online_test.test_settings yaksh
- coverage run -p manage.py test -v 2 --settings online_test.test_settings grades
+ - coverage run -p manage.py test -v 2 --settings online_test.test_settings api
- coverage run -p manage.py test -v 2 --settings online_test.test_settings yaksh.live_server_tests.load_test
after_success:
diff --git a/api/__init__.py b/api/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/api/__init__.py
diff --git a/api/apps.py b/api/apps.py
new file mode 100644
index 0000000..d87006d
--- /dev/null
+++ b/api/apps.py
@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+
+class ApiConfig(AppConfig):
+ name = 'api'
diff --git a/api/serializers.py b/api/serializers.py
new file mode 100644
index 0000000..919e429
--- /dev/null
+++ b/api/serializers.py
@@ -0,0 +1,25 @@
+from rest_framework import serializers
+from yaksh.models import Question, Quiz, QuestionPaper, AnswerPaper
+
+
+class QuestionSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = Question
+ fields = '__all__'
+
+
+class QuizSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = Quiz
+ fields = '__all__'
+
+
+class QuestionPaperSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = QuestionPaper
+ fields = '__all__'
+
+class AnswerPaperSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = AnswerPaper
+ fields = '__all__'
diff --git a/api/tests.py b/api/tests.py
new file mode 100644
index 0000000..0930685
--- /dev/null
+++ b/api/tests.py
@@ -0,0 +1,888 @@
+from django.test import TestCase
+from django.core.urlresolvers import reverse
+from django.contrib.auth.models import User
+from rest_framework.test import APIClient
+from rest_framework import status
+from yaksh.models import (
+ Question, Quiz, QuestionPaper, QuestionSet,
+ AnswerPaper, Course, LearningModule, LearningUnit, StandardTestCase,
+ McqTestCase, Profile
+)
+from api.serializers import (
+ QuestionSerializer, QuizSerializer
+ QuestionPaperSerializer, AnswerPaperSerializer
+)
+from datetime import datetime
+import pytz
+from textwrap import dedent
+from yaksh.settings import SERVER_POOL_PORT
+from yaksh.code_server import ServerPool
+from yaksh import settings
+from threading import Thread
+import time
+import json
+
+
+class QuestionListTestCase(TestCase):
+ """ Test get all questions and create a new question """
+
+ def setUp(self):
+ self.client = APIClient()
+ self.username = 'demo'
+ self.password = 'demo'
+ self.user = User.objects.create_user(username=self.username,
+ password=self.password)
+ Question.objects.create(summary='test question 1', language='python',
+ type='mcq', user=self.user)
+ Question.objects.create(summary='test question 2', language='python',
+ type='mcq', user=self.user)
+
+
+ def test_get_all_questions_anonymous(self):
+ # When
+ response = self.client.get(reverse('api:questions'))
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
+
+ def test_get_all_questions(self):
+ # Given
+ questions = Question.objects.filter(user=self.user)
+ serializer = QuestionSerializer(questions, many=True)
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.get(reverse('api:questions'))
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
+ self.assertEqual(len(response.data), 2)
+ self.assertEqual(response.data, serializer.data)
+
+ def test_create_question_invalid_data(self):
+ # Given
+ data = {'summary': 'Add test question', 'user': self.user.id}
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.post(reverse('api:questions'), data)
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
+ self.assertFalse(Question.objects.filter(
+ summary='Add test question').exists())
+
+ def test_create_question_valid_data(self):
+ # Given
+ data = {'summary': 'Add test question', 'description': 'test',
+ 'language': 'python', 'type': 'mcq', 'user': self.user.id}
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.post(reverse('api:questions'), data)
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_201_CREATED)
+ self.assertTrue(Question.objects.filter(
+ summary='Add test question').exists())
+
+ def tearDown(self):
+ self.client.logout()
+ User.objects.all().delete()
+ Question.objects.all().delete()
+
+
+class QuestionDetailTestCase(TestCase):
+ """ Test get, update or delete a question """
+
+ def setUp(self):
+ self.client = APIClient()
+ self.username = 'demo'
+ self.password = 'demo'
+ self.otherusername = 'otheruser'
+ self.user = User.objects.create_user(username=self.username,
+ password=self.password)
+ self.otheruser = User.objects.create_user(username=self.otherusername,
+ password=self.password)
+ Question.objects.create(summary='test question', language='python',
+ type='mcq', user=self.user)
+ Question.objects.create(summary='delete question', language='python',
+ type='mcq', user=self.user)
+ Question.objects.create(summary='Created by other user', language='python',
+ type='mcq', user=self.otheruser)
+
+ def test_get_question_anonymous(self):
+ # Given
+ question = Question.objects.get(summary='test question')
+ # When
+ response = self.client.get(reverse('api:question',
+ kwargs={'pk': question.id}))
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
+
+ def test_get_question_invalid_pk(self):
+ # Given
+ invalid_pk = 3243
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.get(reverse('api:question',
+ kwargs={'pk': invalid_pk}))
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
+
+ def test_get_question(self):
+ # Given
+ question = Question.objects.get(summary='test question')
+ serializer = QuestionSerializer(question)
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.get(reverse('api:question',
+ kwargs={'pk': question.id}))
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
+ self.assertEqual(response.data, serializer.data)
+
+ def test_get_question_not_own(self):
+ # Given
+ question = Question.objects.get(summary='Created by other user')
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.get(reverse('api:question',
+ kwargs={'pk': question.id}))
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
+
+ def test_edit_question_anonymous(self):
+ # Given
+ question = Question.objects.get(summary='test question')
+ data = {'summary': 'Edited test question', 'description': 'test',
+ 'language': 'python', 'type': 'mcq', 'user': self.user.id}
+ # When
+ response = self.client.put(reverse('api:question',
+ kwargs={'pk': question.id}), data)
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
+
+ def test_edit_question_invalid_data(self):
+ # Given
+ question = Question.objects.get(summary='test question')
+ data = {'summary': 'Edited test question', 'user': self.user.id}
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.put(reverse('api:question',
+ kwargs={'pk': question.id}), data)
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
+
+ def test_edit_question(self):
+ # Given
+ question = Question.objects.get(summary='test question')
+ data = {'summary': 'Edited test question', 'description': 'test',
+ 'language': 'python', 'type': 'mcq', 'user': self.user.id}
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.put(reverse('api:question',
+ kwargs={'pk': question.id}), data)
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
+ question = Question.objects.get(pk=question.pk)
+ self.assertEqual(question.summary, 'Edited test question')
+
+ def test_delete_question_anonymous(self):
+ # Given
+ question = Question.objects.get(summary='delete question')
+ # When
+ response = self.client.delete(reverse('api:question',
+ kwargs={'pk':question.id}))
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
+
+ def test_delete_question_not_own(self):
+ # Given
+ question = Question.objects.get(summary='Created by other user')
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.delete(reverse('api:question',
+ kwargs={'pk':question.id}))
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
+ self.assertTrue(Question.objects.filter(pk=question.id).exists())
+
+ def test_delete_question(self):
+ # Given
+ question = Question.objects.get(summary='delete question')
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.delete(reverse('api:question',
+ kwargs={'pk':question.id}))
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
+ self.assertFalse(Question.objects.filter(pk=question.id).exists())
+
+ def tearDown(self):
+ self.client.logout()
+ User.objects.all().delete()
+ Question.objects.all().delete()
+
+
+class QuestionPaperListTestCase(TestCase):
+ """ Test get all question paper and create a new question paper """
+
+ def setUp(self):
+ self.client = APIClient()
+ self.username = 'demo'
+ self.otherusername = 'otheruser'
+ self.password = 'demo'
+ self.user = User.objects.create_user(username=self.username,
+ password=self.password)
+ self.otheruser = User.objects.create_user(username=self.otherusername,
+ password=self.password)
+ self.quiz1 = Quiz.objects.create(description='Quiz1', creator=self.user)
+ self.quiz2 = Quiz.objects.create(description='Quiz2', creator=self.user)
+ self.quiz3 = Quiz.objects.create(description='Quiz3',
+ creator=self.otheruser)
+
+ self.quiz4 = Quiz.objects.create(description='Quiz4', creator=self.user)
+ self.quiz5 = Quiz.objects.create(description='Quiz5', creator=self.user)
+ self.quiz6 = Quiz.objects.create(description='Quiz6',
+ creator=self.otheruser)
+ self.questionpaper = QuestionPaper.objects.create(quiz=self.quiz1)
+ self.questionpaper2 = QuestionPaper.objects.create(quiz=self.quiz2)
+ QuestionPaper.objects.create(quiz=self.quiz3)
+
+ self.question1 = Question.objects.create(summary='Q1', user=self.user,
+ language='python', type='mcq')
+ self.question2 = Question.objects.create(summary='Q2', user=self.user,
+ language='python', type='mcq')
+ self.question3 = Question.objects.create(summary='Q3', user=self.user,
+ language='python', type='mcq')
+ self.question4 = Question.objects.create(summary='Q4', user=self.user,
+ language='python', type='mcq')
+ self.question5 = Question.objects.create(summary='Q5', user=self.otheruser,
+ language='python', type='mcq')
+ self.questionset = QuestionSet.objects.create(marks=1, num_questions=1)
+ self.questionset.questions.add(self.question3)
+ self.questionset.questions.add(self.question4)
+ self.questionset.save()
+ self.questionpaper.fixed_questions.add(self.question1)
+ self.questionpaper.fixed_questions.add(self.question2)
+ self.questionpaper.random_questions.add(self.questionset)
+ self.questionpaper.save()
+ self.questionpaper.update_total_marks()
+
+ def test_get_all_questionpapers_anonymous(self):
+ # When
+ response = self.client.get(reverse('api:questionpapers'))
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
+
+ def test_get_all_questionpaper(self):
+ # Given
+ questionpapers = QuestionPaper.objects.filter(
+ quiz__in=[self.quiz1, self.quiz2])
+ serializer = QuestionPaperSerializer(questionpapers, many=True)
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.get(reverse('api:questionpapers'))
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
+ self.assertEqual(len(response.data), 2)
+ self.assertEqual(response.data, serializer.data)
+
+ def test_create_questionpaper_invalid_data(self):
+ # Given
+ data = {'fixed_questions': [self.question1.id], 'user': self.user.id}
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.post(reverse('api:questionpapers'), data)
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
+
+ def test_create_questionpaper_valid_data(self):
+ # Given
+ data = {'quiz': self.quiz4.id,
+ 'fixed_questions': [self.question1.id, self.question2.id],
+ 'random_questions': [self.questionset.id]
+ }
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.post(reverse('api:questionpapers'), data)
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_201_CREATED)
+ self.assertTrue(QuestionPaper.objects.filter(quiz=self.quiz4).exists())
+
+ def test_create_questionpaper_not_own_quiz(self):
+ # Given
+ data = {'quiz': self.quiz5.id, 'fixed_questions':[self.question1.id],
+ 'random_questions': [self.questionset.id]}
+ # When
+ self.client.login(username=self.otherusername, password=self.password)
+ response = self.client.post(reverse('api:questionpapers'), data)
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
+
+ def test_create_questionpaper_not_own_questions(self):
+ # Given
+ data = {'quiz': self.quiz6.id,
+ 'fixed_questions':[self.question1.id, self.question5.id],
+ 'random_questions': [self.questionset.id]
+ }
+ # When
+ self.client.login(username=self.otherusername, password=self.password)
+ response = self.client.post(reverse('api:questionpapers'), data)
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)\
+
+ def test_create_questionpaper_not_own_questionsets(self):
+ # Given
+ data = {'quiz': self.quiz6.id,
+ 'fixed_questions':[self.question5.id],
+ 'random_questions': [self.questionset.id]
+ }
+ # When
+ self.client.login(username=self.otherusername, password=self.password)
+ response = self.client.post(reverse('api:questionpapers'), data)
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
+
+ def test_create_questionpaper_already_exists(self):
+ # Given
+ data = {'quiz': self.quiz1.id,
+ 'fixed_questions': [self.question1.id],
+ 'random_questions': [self.questionset.id]
+ }
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.post(reverse('api:questionpapers'), data)
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_409_CONFLICT)
+ self.assertEqual(QuestionPaper.objects.filter(
+ quiz=self.quiz1).count(), 1)
+
+ # QuestionPaper Detail Tests
+ def test_get_questionpaper(self):
+ # Given
+ questionpaper = self.questionpaper
+ serializer = QuestionPaperSerializer(questionpaper)
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.get(reverse('api:questionpaper',
+ kwargs={'pk': questionpaper.id}))
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
+ self.assertEqual(response.data, serializer.data)
+
+ def test_get_questionpaper_not_own(self):
+ # Given
+ questionpaper = self.questionpaper
+ # When
+ self.client.login(username=self.otherusername, password=self.password)
+ response = self.client.get(reverse('api:questionpaper',
+ kwargs={'pk': questionpaper.id}))
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
+
+
+ def test_edit_questionpaper(self):
+ # Given
+ questionpaper = self.questionpaper2
+ data = {'quiz': self.quiz5.id,
+ 'fixed_questions': [self.question1.id, self.question2.id],
+ 'random_questions': [self.questionset.id]
+ }
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.put(reverse('api:questionpaper',
+ kwargs={'pk': questionpaper.id}), data)
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
+ questionpaper = QuestionPaper.objects.get(pk=questionpaper.id)
+ self.assertEqual(questionpaper.quiz.id, self.quiz5.id)
+
+
+ def test_delete_questionpaper(self):
+ # Given
+ questionpaper = self.questionpaper2
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.delete(reverse('api:questionpaper',
+ kwargs={'pk':questionpaper.id}))
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
+ self.assertFalse(QuestionPaper.objects.filter(quiz=self.quiz2).exists())
+
+ def tearDown(self):
+ self.client.logout()
+ User.objects.all().delete()
+ Question.objects.all().delete()
+ QuestionPaper.objects.all().delete()
+ Quiz.objects.all().delete()
+
+
+class QuizListTestCase(TestCase):
+ """ Test get all quizzes and create a new quiz """
+
+ def setUp(self):
+ self.client = APIClient()
+ self.username = 'demo'
+ self.password = 'demo'
+ self.user = User.objects.create_user(username=self.username,
+ password=self.password)
+ Quiz.objects.create(description='Test Quiz 1', creator=self.user)
+ Quiz.objects.create(description='Test Quiz 2', creator=self.user)
+
+ def test_get_all_quizzes_anonymous(self):
+ # When
+ response = self.client.get(reverse('api:quizzes'))
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
+
+
+ def test_get_all_quizzes(self):
+ # Given
+ quizzes = Quiz.objects.filter(creator=self.user)
+ serializer = QuizSerializer(quizzes, many=True)
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.get(reverse('api:quizzes'))
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
+ self.assertEqual(len(response.data), 2)
+ self.assertEqual(response.data, serializer.data)
+
+ def test_create_quiz_invalid_data(self):
+ # Given
+ data = {'creator': self.user.id}
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.post(reverse('api:quizzes'), data)
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
+
+ def test_create_quiz_valid_data(self):
+ # Given
+ data = {'description': 'Added quiz', 'creator': self.user.id}
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.post(reverse('api:quizzes'), data)
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_201_CREATED)
+ self.assertTrue(Quiz.objects.filter(description='Added quiz').exists())
+
+ def tearDown(self):
+ self.client.logout()
+ User.objects.all().delete()
+ Quiz.objects.all().delete()
+
+
+class QuizDetailTestCase(TestCase):
+ """ Test get, update or delete a quiz """
+
+ def setUp(self):
+ self.client = APIClient()
+ self.username = 'quizuser'
+ self.password = 'demo'
+ self.otherusername = 'quizuser2'
+ self.user = User.objects.create_user(username=self.username,
+ password=self.password)
+ self.otheruser = User.objects.create_user(username=self.otherusername,
+ password=self.password)
+ Quiz.objects.create(description='Quiz1', creator=self.user)
+ Quiz.objects.create(description='Quiz2', creator=self.user)
+ Quiz.objects.create(description='delete quiz', creator=self.user)
+ Quiz.objects.create(description='Quiz3', creator=self.otheruser)
+
+ def test_get_quiz_anonymous(self):
+ # Given
+ quiz = Quiz.objects.get(description='Quiz1')
+ # When
+ response = self.client.get(reverse('api:quiz', kwargs={'pk': quiz.id}))
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
+
+ def test_get_quiz_invalid_pk(self):
+ # Given
+ invalid_pk = 3242
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.get(reverse('api:quiz',
+ kwargs={'pk': invalid_pk}))
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
+
+ def test_get_quiz(self):
+ # Given
+ quiz = Quiz.objects.get(description='Quiz1')
+ serializer = QuizSerializer(quiz)
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.get(reverse('api:quiz',
+ kwargs={'pk': quiz.id}))
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
+ self.assertEqual(response.data, serializer.data)
+
+ def test_get_quiz_not_own(self):
+ # Given
+ quiz = Quiz.objects.get(description='Quiz3')
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.get(reverse('api:quiz', kwargs={'pk': quiz.id}))
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
+
+ def test_edit_quiz_anonymous(self):
+ # Given
+ quiz = Quiz.objects.get(description='Quiz1')
+ data = {'description': 'Quiz1 Edited', 'creator': self.user.id}
+ # When
+ response = self.client.put(reverse('api:quiz', kwargs={'pk': quiz.id}),
+ data)
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
+
+ def test_edit_quiz_invalid_data(self):
+ # Given
+ quiz = Quiz.objects.get(description='Quiz1')
+ data = {'creator': self.user.id}
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.put(reverse('api:quiz', kwargs={'pk': quiz.id}),
+ data)
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
+
+ def test_edit_quiz(self):
+ # Given
+ quiz = Quiz.objects.get(description='Quiz2')
+ data = {'description': 'Quiz2 edited', 'creator': self.user.id}
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.put(reverse('api:quiz', kwargs={'pk': quiz.id}),
+ data)
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
+ quiz = Quiz.objects.get(pk=quiz.id)
+ self.assertEqual(quiz.description, 'Quiz2 edited')
+
+ def test_delete_quiz_anonymous(self):
+ # Given
+ quiz = Quiz.objects.get(description='delete quiz')
+ # When
+ response = self.client.delete(reverse('api:quiz',
+ kwargs={'pk': quiz.id}))
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
+
+ def test_delete_quiz_not_own(self):
+ # Given
+ quiz = Quiz.objects.get(description='Quiz3')
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.delete(reverse('api:quiz',
+ kwargs={'pk': quiz.id}))
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
+ self.assertTrue(Quiz.objects.filter(pk=quiz.id).exists())
+
+ def test_delete_quiz(self):
+ # Given
+ quiz = Quiz.objects.get(description='delete quiz')
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.delete(reverse('api:quiz',
+ kwargs={'pk':quiz.id}))
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
+ self.assertFalse(Quiz.objects.filter(pk=quiz.id).exists())
+
+ def tearDown(self):
+ self.client.logout()
+ User.objects.all().delete()
+ Quiz.objects.all().delete()
+
+
+class AnswerPaperListTestCase(TestCase):
+
+ def setUp(self):
+ self.client = APIClient()
+ self.username = 'demo'
+ self.otherusername = 'otheruser'
+ self.studentusername = 'student'
+ self.password = 'demo'
+ self.user = User.objects.create_user(username=self.username,
+ password=self.password)
+ self.otheruser = User.objects.create_user(username=self.otherusername,
+ password=self.password)
+ self.student = User.objects.create_user(username=self.studentusername,
+ password='demo')
+ self.quiz1 = Quiz.objects.create(description='Quiz1', creator=self.user)
+ self.quiz2 = Quiz.objects.create(description='Quiz2',
+ creator=self.otheruser)
+ self.questionpaper1 = QuestionPaper.objects.create(quiz=self.quiz1)
+ self.questionpaper2 = QuestionPaper.objects.create(quiz=self.quiz2)
+ self.question1 = Question.objects.create(summary='Q1', user=self.user,
+ language='python', type='mcq')
+ self.question2 = Question.objects.create(summary='Q5', user=self.otheruser,
+ language='python', type='mcq')
+ self.questionpaper1.fixed_questions.add(self.question1)
+ self.questionpaper2.fixed_questions.add(self.question2)
+ self.questionpaper1.save()
+ self.questionpaper2.save()
+ self.questionpaper1.update_total_marks()
+ self.questionpaper2.update_total_marks()
+ self.answerpaper1 = AnswerPaper.objects.create(user=self.user,
+ question_paper=self.questionpaper1, attempt_number=1,
+ start_time=datetime(2015, 10, 9, 10, 8, 15, 0, tzinfo=pytz.utc),
+ end_time=datetime(2015, 10, 9, 10, 28, 15, 0, tzinfo=pytz.utc))
+ self.answerpaper2 = AnswerPaper.objects.create(user=self.otheruser,
+ question_paper=self.questionpaper2, attempt_number=1,
+ start_time=datetime(2015, 10, 9, 10, 8, 15, 0, tzinfo=pytz.utc),
+ end_time=datetime(2015, 10, 9, 10, 28, 15, 0, tzinfo=pytz.utc))
+
+ self.course = Course.objects.create(name="Python Course",
+ enrollment="Enroll Request",
+ creator=self.user)
+
+ # Learing module
+ learning_module = LearningModule.objects.create(
+ name='LM1', description='module one', creator=self.user
+ )
+ learning_unit_quiz = LearningUnit.objects.create(quiz=self.quiz1,
+ type='quiz', order=1)
+ learning_module.learning_unit.add(learning_unit_quiz)
+ learning_module.save()
+ self.course.learning_module.add(learning_module)
+ self.course.students.add(self.student)
+ self.course.save()
+
+
+ def test_get_all_answerpapers(self):
+ # Given
+ answerpapers = [self.answerpaper1]
+ serializer = AnswerPaperSerializer(answerpapers, many=True)
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.get(reverse('api:answerpapers'))
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
+ self.assertEqual(len(response.data), 1)
+ self.assertEqual(response.data, serializer.data)
+
+ def test_create_answerpaper_valid_data(self):
+ # Given
+ data = {'question_paper': self.questionpaper1.id,
+ 'attempt_number': 1, 'course': self.course.id
+ }
+ # When
+ self.client.login(username=self.studentusername, password=self.password)
+ response = self.client.post(reverse('api:answerpapers'), data)
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_201_CREATED)
+ answerpapers = AnswerPaper.objects.filter(question_paper=self.questionpaper1,
+ user=self.student, attempt_number=1,
+ course=self.course)
+ self.assertTrue(answerpapers.exists())
+ self.assertEqual(answerpapers.count(), 1)
+
+ def test_create_answerpaper_invalid_data(self):
+ # Given
+ data = {'question_paper': self.questionpaper1.id}
+ # When
+ self.client.login(username=self.studentusername, password=self.password)
+ response = self.client.post(reverse('api:answerpapers'), data)
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
+
+ def test_create_answerpaper_not_enrolled(self):
+ # Given
+ data = {'question_paper': self.questionpaper1.id,
+ 'attempt_number': 1, 'course': self.course.id
+ }
+ # When
+ self.client.login(username=self.otherusername, password=self.password)
+ response = self.client.post(reverse('api:answerpapers'), data)
+ # Then
+ self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
+ answerpapers = AnswerPaper.objects.filter(question_paper=self.questionpaper1,
+ user=self.otheruser, attempt_number=1,
+ course=self.course)
+ self.assertFalse(answerpapers.exists())
+ self.assertEqual(answerpapers.count(), 0)
+
+ def tearDown(self):
+ self.client.logout()
+ User.objects.all().delete()
+ Question.objects.all().delete()
+ QuestionPaper.objects.all().delete()
+ Quiz.objects.all().delete()
+ AnswerPaper.objects.all().delete()
+
+
+class AnswerValidatorTestCase(TestCase):
+
+ @classmethod
+ def setUpClass(self):
+ self.client = APIClient()
+ self.username = 'demo'
+ self.password = 'demo'
+ self.user = User.objects.create_user(username=self.username,
+ password=self.password)
+ Profile.objects.create(user=self.user)
+ self.quiz = Quiz.objects.create(description='Quiz', creator=self.user)
+ self.questionpaper = QuestionPaper.objects.create(quiz=self.quiz)
+ self.question1 = Question.objects.create(summary='Q1', user=self.user,
+ points=1.0, language='python', type='code')
+ self.question2 = Question.objects.create(summary='Q2', user=self.user,
+ points=1.0, language='python', type='mcq')
+ self.question3 = Question.objects.create(summary='Q3', user=self.user,
+ points=1.0, language='python', type='mcc')
+ self.question4 = Question.objects.create(summary='Q4', user=self.user,
+ points=1.0, language='python', type='mcq')
+ self.question5 = Question.objects.create(summary='Q5', user=self.user,
+ points=1.0, language='python', type='mcq')
+ self.assertion_testcase = StandardTestCase(
+ question=self.question1,
+ test_case='assert add(1, 3) == 4',
+ type='standardtestcase'
+ )
+ self.assertion_testcase.save()
+ self.mcq_based_testcase1 = McqTestCase(
+ options='a',
+ question=self.question2,
+ correct=True,
+ type='mcqtestcase'
+ )
+ self.mcq_based_testcase1.save()
+ self.mcq_based_testcase2 = McqTestCase(
+ options='b',
+ question=self.question2,
+ correct=False,
+ type='mcqtestcase'
+ )
+ self.mcq_based_testcase2.save()
+ self.mcc_based_testcase = McqTestCase(
+ question=self.question3,
+ options='a',
+ correct=True,
+ type='mcqtestcase'
+ )
+ self.mcc_based_testcase.save()
+ self.questionset = QuestionSet.objects.create(marks=1, num_questions=1)
+ self.questionset.questions.add(self.question3)
+ self.questionset.questions.add(self.question4)
+ self.questionset.save()
+ self.questionpaper.fixed_questions.add(self.question1)
+ self.questionpaper.fixed_questions.add(self.question2)
+ self.questionpaper.random_questions.add(self.questionset)
+ self.questionpaper.save()
+ self.questionpaper.update_total_marks()
+ self.course = Course.objects.create(name="Python Course",
+ enrollment="Enroll Request",
+ creator=self.user)
+ # Learing module
+ learning_module = LearningModule.objects.create(
+ name='LM1', description='module one', creator=self.user
+ )
+ learning_unit_quiz = LearningUnit.objects.create(quiz=self.quiz,
+ type='quiz', order=1)
+ learning_module.learning_unit.add(learning_unit_quiz)
+ learning_module.save()
+ self.course.learning_module.add(learning_module)
+ self.course.students.add(self.user)
+ self.course.save()
+ self.ip = '127.0.0.1'
+ self.answerpaper = self.questionpaper.make_answerpaper(
+ self.user, self.ip, 1, self.course.id
+ )
+
+ settings.code_evaluators['python']['standardtestcase'] = \
+ "yaksh.python_assertion_evaluator.PythonAssertionEvaluator"
+ server_pool = ServerPool(n=1, pool_port=SERVER_POOL_PORT)
+ self.server_pool = server_pool
+ self.server_thread = t = Thread(target=server_pool.run)
+ t.start()
+
+ @classmethod
+ def tearDownClass(self):
+ self.client.logout()
+ User.objects.all().delete()
+ Question.objects.all().delete()
+ QuestionPaper.objects.all().delete()
+ Quiz.objects.all().delete()
+ AnswerPaper.objects.all().delete()
+ self.server_pool.stop()
+ self.server_thread.join()
+ settings.code_evaluators['python']['standardtestcase'] = \
+ "python_assertion_evaluator.PythonAssertionEvaluator"
+
+ def test_correct_mcq(self):
+ # Given
+ data = {'answer': str( self.mcq_based_testcase1.id)}
+ answerpaper_id = self.answerpaper.id
+ question_id = self.question2.id
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.post(reverse('api:validators',
+ kwargs={'answerpaper_id': answerpaper_id, 'question_id': question_id}), data)
+ # Then
+ self.assertTrue(response.status_code, status.HTTP_200_OK)
+ self.assertTrue(response.data['success'])
+ answerpaper = AnswerPaper.objects.get(user=self.user, course=self.course,
+ attempt_number=1,
+ question_paper=self.questionpaper)
+ self.assertTrue(answerpaper.marks_obtained > 0)
+
+
+ def test_wrong_mcq(self):
+ # Given
+ data = {'answer': str( self.mcq_based_testcase2.id)}
+ answerpaper_id = self.answerpaper.id
+ question_id = self.question2.id
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.post(reverse('api:validators',
+ kwargs={'answerpaper_id': answerpaper_id, 'question_id': question_id}), data)
+ # Then
+ self.assertTrue(response.status_code, status.HTTP_200_OK)
+ self.assertFalse(response.data['success'])
+
+ def test_correct_mcc(self):
+ # Given
+ data = {'answer': str( self.mcc_based_testcase.id)}
+ answerpaper_id = self.answerpaper.id
+ question_id = self.question3.id
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.post(reverse('api:validators',
+ kwargs={'answerpaper_id': answerpaper_id, 'question_id': question_id}), data)
+ # Then
+ self.assertTrue(response.status_code, status.HTTP_200_OK)
+ self.assertTrue(response.data['success'])
+ answerpaper = AnswerPaper.objects.get(user=self.user, course=self.course,
+ attempt_number=1,
+ question_paper=self.questionpaper)
+ self.assertTrue(answerpaper.marks_obtained > 0)
+
+ def test_correct_code(self):
+ # Given
+ answer = dedent("""\
+ def add(a,b):
+ return a+b
+ """)
+ data = {'answer': answer}
+ answerpaper_id = self.answerpaper.id
+ question_id = self.question1.id
+ # When
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.post(reverse('api:validators',
+ kwargs={'answerpaper_id': answerpaper_id, 'question_id': question_id}), data)
+ # Then
+ self.assertTrue(response.status_code, status.HTTP_200_OK)
+ self.assertEqual(response.data['status'], 'running')
+ uid = response.data['uid']
+ time.sleep(2)
+ response = self.client.get(reverse('api:validator', kwargs={'uid': uid}))
+ self.assertTrue(response.status_code, status.HTTP_200_OK)
+ answerpaper = AnswerPaper.objects.get(user=self.user, course=self.course,
+ attempt_number=1,
+ question_paper=self.questionpaper)
+ if response.data['status'] == 'done':
+ result = json.loads(response.data['result'])
+ self.assertTrue(result['success'])
+ else:
+ self.assertEqual(response.data['status'], 'running')
+
diff --git a/api/urls.py b/api/urls.py
new file mode 100644
index 0000000..be276da
--- /dev/null
+++ b/api/urls.py
@@ -0,0 +1,23 @@
+from django.conf.urls import url
+from rest_framework.urlpatterns import format_suffix_patterns
+from api import views
+
+
+urlpatterns = [
+ url(r'questions/$', views.QuestionList.as_view(), name='questions'),
+ url(r'questions/(?P<pk>[0-9]+)/$', views.QuestionDetail.as_view(),
+ name='question'),
+ url(r'quizzes/$', views.QuizList.as_view(), name='quizzes'),
+ url(r'quizzes/(?P<pk>[0-9]+)/$', views.QuizDetail.as_view(), name='quiz'),
+ url(r'questionpapers/$', views.QuestionPaperList.as_view(),
+ name='questionpapers'),
+ url(r'questionpapers/(?P<pk>[0-9]+)/$', views.QuestionPaperDetail.as_view(),
+ name='questionpaper'),
+ url(r'answerpapers/$', views.AnswerPaperList.as_view(), name='answerpapers'),
+ url(r'validate/(?P<answerpaper_id>[0-9]+)/(?P<question_id>[0-9]+)/$',
+ views.AnswerValidator.as_view(), name='validators'),
+ url(r'validate/(?P<uid>[0-9]+)/$',
+ views.AnswerValidator.as_view(), name='validator'),
+]
+
+urlpatterns = format_suffix_patterns(urlpatterns)
diff --git a/api/views.py b/api/views.py
new file mode 100644
index 0000000..14e04f0
--- /dev/null
+++ b/api/views.py
@@ -0,0 +1,330 @@
+from yaksh.models import (
+ Question, Quiz, QuestionPaper, QuestionSet, AnswerPaper, Course, Answer
+)
+from api.serializers import (
+ QuestionSerializer, QuizSerializer, QuestionPaperSerializer,
+ AnswerPaperSerializer
+)
+from rest_framework.views import APIView
+from rest_framework.response import Response
+from rest_framework import status
+from rest_framework import permissions
+from django.http import Http404
+from yaksh.code_server import get_result as get_result_from_code_server
+from yaksh.settings import SERVER_POOL_PORT, SERVER_HOST_NAME
+import json
+
+
+class QuestionList(APIView):
+ """ List all questions or create a new question. """
+
+ def get(self, request, format=None):
+ questions = Question.objects.filter(user=request.user)
+ serializer = QuestionSerializer(questions, many=True)
+ return Response(serializer.data)
+
+
+ def post(self, request, format=None):
+ serializer = QuestionSerializer(data=request.data)
+ if serializer.is_valid():
+ serializer.save()
+ return Response(serializer.data, status=status.HTTP_201_CREATED)
+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
+
+
+class QuestionDetail(APIView):
+ """ Retrieve, update or delete a question """
+
+ def get_question(self, pk, user):
+ try:
+ return Question.objects.get(pk=pk, user=user)
+ except Question.DoesNotExist:
+ raise Http404
+
+ def get(self, request, pk, format=None):
+ question = self.get_question(pk, request.user)
+ serializer = QuestionSerializer(question)
+ return Response(serializer.data)
+
+ def put(self, request, pk, format=None):
+ question = self.get_question(pk, request.user)
+ serializer = QuestionSerializer(question, data=request.data)
+ if serializer.is_valid():
+ serializer.save()
+ return Response(serializer.data)
+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
+
+ def delete(self, request, pk, format=None):
+ question = self.get_question(pk, request.user)
+ question.delete()
+ return Response(status=status.HTTP_204_NO_CONTENT)
+
+
+class AnswerPaperList(APIView):
+
+ def get_questionpaper(self, pk):
+ try:
+ return QuestionPaper.objects.get(pk=pk)
+ except QuestionPaper.DoesNotExist:
+ raise Http404
+
+ def get_course(self, pk):
+ try:
+ return Course.objects.get(pk=pk)
+ except Course.DoesNotExist:
+ raise Http404
+
+ def get_answerpapers(self, user):
+ return AnswerPaper.objects.filter(question_paper__quiz__creator=user)
+
+ def get(self, request, format=None):
+ user = request.user
+ answerpapers = self.get_answerpapers(user)
+ serializer = AnswerPaperSerializer(answerpapers, many=True)
+ return Response(serializer.data)
+
+ def is_user_allowed(self, user, course):
+ ''' if user is student or teacher or creator then allow '''
+ return user in course.students.all() or user in course.teachers.all() or user == course.creator
+
+ def post(self, request, format=None):
+ try:
+ questionpaperid = request.data['question_paper']
+ attempt_number = request.data['attempt_number']
+ course_id = request.data['course']
+ except KeyError:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ user = request.user
+ ip = request.META['REMOTE_ADDR']
+ questionpaper = self.get_questionpaper(questionpaperid)
+ course = self.get_course(course_id)
+ if not self.is_user_allowed(user, course):
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ answerpaper = questionpaper.make_answerpaper(user, ip, attempt_number, course_id)
+ serializer = AnswerPaperSerializer(answerpaper)
+ return Response(serializer.data, status=status.HTTP_201_CREATED)
+
+
+class AnswerValidator(APIView):
+
+ def get_answerpaper(self, pk, user):
+ try:
+ return AnswerPaper.objects.get(pk=pk, user=user)
+ except AnswerPaper.DoesNotExist:
+ raise Http404
+
+ def get_question(self, pk, answerpaper):
+ try:
+ question = Question.objects.get(pk=pk)
+ if question in answerpaper.questions.all():
+ return question
+ else:
+ raise Http404
+ except AnswerPaper.DoesNotExist:
+ raise Http404
+
+ def get_answer(self, pk):
+ try:
+ return Answer.objects.get(pk=pk)
+ except Answer.DoesNotExist:
+ raise Http404
+
+ def post(self, request, answerpaper_id, question_id, format=None):
+ try:
+ user_answer = request.data['answer']
+ except KeyError:
+ return Response(status=status.HTTP_400_BAD_REQUEST)
+ user = request.user
+ answerpaper = self.get_answerpaper(answerpaper_id, user)
+ question = self.get_question(question_id, answerpaper)
+ # save answer uid
+ answer = Answer.objects.create(question=question, answer=user_answer)
+ answerpaper.answers.add(answer)
+ answerpaper.save()
+ json_data = None
+ if question.type in ['code', 'upload']:
+ json_data = question.consolidate_answer_data(user_answer, user)
+ result = answerpaper.validate_answer(user_answer, question, json_data, answer.id)
+
+ # updaTE RESult
+ if question.type not in ['code', 'upload']:
+ if result.get('success'):
+ answer.correct = True
+ answer.marks = question.points
+ answer.error = json.dumps(result.get('error'))
+ answer.save()
+ answerpaper.update_marks(state='inprogress')
+ return Response(result)
+
+ def get(self, request, uid):
+ answer = self.get_answer(uid)
+ url = '{0}:{1}'.format(SERVER_HOST_NAME, SERVER_POOL_PORT)
+ result = get_result_from_code_server(url, uid)
+ # update result
+ if result['status'] == 'done':
+ final_result = json.loads(result.get('result'))
+ answer.error = json.dumps(result.get('error'))
+ if final_result.get('success'):
+ answer.correct = True
+ answer.marks = answer.question.points
+ answer.save()
+ answerpaper = answer.answerpaper_set.get()
+ answerpaper.update_marks(state='inprogress')
+ return Response(result)
+
+
+class QuizList(APIView):
+ """ List all quizzes or create a new quiz """
+
+ def get(self, request, format=None):
+ quizzes = Quiz.objects.filter(creator=request.user)
+ serializer = QuizSerializer(quizzes, many=True)
+ return Response(serializer.data)
+
+ def post(self, request, format=None):
+ serializer = QuizSerializer(data=request.data)
+ if serializer.is_valid():
+ serializer.save()
+ return Response(serializer.data, status=status.HTTP_201_CREATED)
+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
+
+
+class QuizDetail(APIView):
+ """ Retrieve, update or delete a quiz """
+
+ def get_quiz(self, pk, user):
+ try:
+ return Quiz.objects.get(pk=pk, creator=user)
+ except Quiz.DoesNotExist:
+ raise Http404
+
+ def get(self, request, pk, format=None):
+ quiz = self.get_quiz(pk, request.user)
+ serializer = QuizSerializer(quiz)
+ return Response(serializer.data)
+
+ def put(self, request, pk, format=None):
+ quiz = self.get_quiz(pk, request.user)
+ serializer = QuizSerializer(quiz, data=request.data)
+ if serializer.is_valid():
+ serializer.save()
+ return Response(serializer.data)
+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
+
+ def delete(self, request, pk, format=None):
+ quiz = self.get_quiz(pk, request.user)
+ quiz.delete()
+ return Response(status=status.HTTP_204_NO_CONTENT)
+
+
+class QuestionPaperList(APIView):
+ """ List all question papers or create a new question paper """
+
+ def get_questionpapers(self, user):
+ return QuestionPaper.objects.filter(quiz__creator=user)
+
+ def questionpaper_exists(self, quiz_id):
+ return QuestionPaper.objects.filter(quiz=quiz_id).exists()
+
+ def check_quiz_creator(self, user, quiz_id):
+ try:
+ Quiz.objects.get(pk=quiz_id, creator=user)
+ except Quiz.DoesNotExist:
+ raise Http404
+
+ def check_questions_creator(self, user, question_ids):
+ for question_id in question_ids:
+ try:
+ Question.objects.get(pk=question_id, user=user)
+ except Question.DoesNotExist:
+ raise Http404
+
+ def check_questionsets_creator(self, user, questionset_ids):
+ for question_id in questionset_ids:
+ try:
+ questionset = QuestionSet.objects.get(pk=question_id)
+ for question in questionset.questions.all():
+ Question.objects.get(pk=question.id, user=user)
+ except (QuestionSet.DoesNotExist, Question.DoesNotExist):
+ raise Http404
+
+ def get(self, request, format=None):
+ questionpapers = self.get_questionpapers(request.user)
+ serializer = QuestionPaperSerializer(questionpapers, many=True)
+ return Response(serializer.data)
+
+ def post(self, request, format=None):
+ serializer = QuestionPaperSerializer(data=request.data)
+ if serializer.is_valid():
+ user = request.user
+ quiz_id = request.data.get('quiz')
+ question_ids = request.data.get('fixed_questions', [])
+ questionset_ids = request.data.get('random_questions', [])
+ if self.questionpaper_exists(quiz_id):
+ return Response({'error': 'Already exists'},
+ status=status.HTTP_409_CONFLICT)
+ self.check_quiz_creator(user, quiz_id)
+ self.check_questions_creator(user, question_ids)
+ self.check_questionsets_creator(user, questionset_ids)
+ serializer.save()
+ return Response(serializer.data, status=status.HTTP_201_CREATED)
+ return Response(serializer.errors, status.HTTP_400_BAD_REQUEST)
+
+
+class QuestionPaperDetail(APIView):
+ """ Retrieve, update or delete a question paper"""
+
+ def get_questionpaper(self, pk, user):
+ try:
+ return QuestionPaper.objects.get(pk=pk, quiz__creator=user)
+ except QuestionPaper.DoesNotExist:
+ raise Http404
+
+ def get(self, request, pk, format=None):
+ questionpaper = self.get_questionpaper(pk, request.user)
+ serializer = QuestionPaperSerializer(questionpaper)
+ return Response(serializer.data)
+
+ def check_quiz_creator(self, user, quiz_id):
+ try:
+ Quiz.objects.get(pk=quiz_id, creator=user)
+ except Quiz.DoesNotExist:
+ raise Http404
+
+ def check_questions_creator(self, user, question_ids):
+ for question_id in question_ids:
+ try:
+ Question.objects.get(pk=question_id, user=user)
+ except Question.DoesNotExist:
+ raise Http404
+
+ def check_questionsets_creator(self, user, questionset_ids):
+ for question_id in questionset_ids:
+ try:
+ questionset = QuestionSet.objects.get(pk=question_id)
+ for question in questionset.questions.all():
+ Question.objects.get(pk=question.id, user=user)
+ except (QuestionSet.DoesNotExist, Question.DoesNotExist):
+ raise Http404
+
+ def put(self, request, pk, format=None):
+ user = request.user
+ questionpaper = self.get_questionpaper(pk, user)
+ serializer = QuestionPaperSerializer(questionpaper, data=request.data)
+ if serializer.is_valid():
+ user = request.user
+ quiz_id = request.data.get('quiz')
+ question_ids = request.data.get('fixed_questions', [])
+ questionset_ids = request.data.get('random_questions', [])
+ self.check_quiz_creator(user, quiz_id)
+ self.check_questions_creator(user, question_ids)
+ self.check_questionsets_creator(user, questionset_ids)
+ serializer.save()
+ return Response(serializer.data)
+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
+
+ def delete(self, request, pk, format=None):
+ questionpaper = self.get_questionpaper(pk, request.user)
+ questionpaper.delete()
+ return Response(status=status.HTTP_204_NO_CONTENT)
+
diff --git a/online_test/settings.py b/online_test/settings.py
index b9a7a2c..1df8a4a 100644
--- a/online_test/settings.py
+++ b/online_test/settings.py
@@ -45,6 +45,8 @@ INSTALLED_APPS = (
'taggit',
'social.apps.django_app.default',
'grades',
+ 'rest_framework',
+ 'api',
)
MIDDLEWARE_CLASSES = (
@@ -187,3 +189,16 @@ SOCIAL_AUTH_FACEBOOK_SCOPE = ['email']
SOCIAL_AUTH_FACEBOOK_PROFILE_EXTRA_PARAMS = {
'fields': 'id, name, email'
}
+
+REST_FRAMEWORK = {
+ # Use Django's standard `django.contrib.auth` permissions,
+ # or allow read-only access for unauthenticated users.
+ 'DEFAULT_AUTHENTICATION_CLASSES': [
+ 'rest_framework.authentication.BasicAuthentication',
+ 'rest_framework.authentication.SessionAuthentication',
+ ],
+ 'DEFAULT_PERMISSION_CLASSES': [
+ 'rest_framework.permissions.IsAuthenticated'
+ ],
+ 'TEST_REQUEST_DEFAULT_FORMAT': 'json'
+}
diff --git a/online_test/urls.py b/online_test/urls.py
index 28c2a26..5517732 100644
--- a/online_test/urls.py
+++ b/online_test/urls.py
@@ -15,5 +15,7 @@ urlpatterns = [
url(r'^', include('social.apps.django_app.urls', namespace='social')),
url(r'^grades/', include('grades.urls', namespace='grades',
app_name='grades')),
+ url(r'^api/', include('api.urls', namespace='api', app_name='api')),
+
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
diff --git a/yaksh/models.py b/yaksh/models.py
index 60b09c5..e3212fd 100644
--- a/yaksh/models.py
+++ b/yaksh/models.py
@@ -1509,6 +1509,7 @@ class QuestionPaper(models.Model):
for question_set in self.random_questions.all():
marks += question_set.marks * question_set.num_questions
self.total_marks = marks
+ self.save()
def _get_questions_for_answerpaper(self):
""" Returns fixed and random questions for the answer paper"""